本文示例代码材料源自Head First设计模式
以前整理自己整理的策略模式的链接:
https://blog.csdn.net/u011109881/article/details/60478840

策略模式思想

核心思想,分离变与不变。
例如原先我们设计了一个动物园系统,这个是个动物园是个不正经的动物园,只有鸭子,比如绿头鸭,塑料玩具鸭,木头鸭子等等。原先的系统已经设计好了,系统中有各种鸭子继承了Duck,并有一个方法swim(假设所有鸭子都会游泳)
类图如下:

要知道,作为程序员,肯定知道需求的变动是很频繁的,现在发生了需求变动。要给原来的鸭子添加飞行的方法。有Java基础的会立马想到在Duck类中添加一个Fly方法。但是,请听我说完需求。现在所需要的飞行方法不是单一的,比如绿头鸭和野鸭等“真正的”鸭子是用翅膀飞的;木头鸭,塑料玩具鸭是不能飞的。马达鸭(一种玩具鸭,可以装电池,利用马达飞行)可以利用马达飞行。这样一来,继承的方式就不太好了。如果硬要使用继承,那么需要在每个子类鸭子重写父类的fly方法。
那么,使用接口呢?比如写出接口基类FlyBehavior。
然后用FlyNoWay接口表示不会飞的鸭子,FlyNoWay继承了FlyBehavior,不会飞的鸭子实现FlyNoWay接口;
用FlyWithWings接口表示会用翅膀飞的鸭子,FlyWithWings继承了FlyBehavior,会用翅膀飞的鸭子实现FlyWithWings接口;
以此类推。这样乍看很好啊,没有什么问题。但是很快我们会发现如果是木头鸭和塑料鸭,它们都实现了FlyNoWay接口,并且都在自己的类中将该方法重写一遍。因此,出现了重复代码。
那么,还有其他什么更好的方式来添加飞行方法吗?有,就是委托。委托这个词看起来很难懂,但是我们可以把委托者和被委托者想成has-a(有一个)的关系。比如上面这个例子,鸭子(被委托者)有一个飞行行为(委托者)
把飞行想成Duck的一个功能,Duck具有该功能,即Duck本身含有飞行行为的实例,可以调用飞行行为的飞行方法。
详细设计方式可以参见类图

示例思路(规划类图)

类结构:

UML类图:

实际代码

  • Duck基类
public abstract class Duck {String name;FlyBehavior flyBehavior;public void swim() {System.out.println("通常,所有鸭子都会游泳");}public String getName() {System.out.println("this is "+name);return name;}public void myFlyBehavior() {if(null == flyBehavior){System.out.println("你还没有给该鸭子赋予飞行方式");return;}flyBehavior.fly();}public void setFlyBehavior(FlyBehavior flyBehavior) {this.flyBehavior = flyBehavior;}
}
  • 实体类MallardDuck
public class MallardDuck extends Duck{public MallardDuck(String n){this.name =n;}
}
  • 实体类ToyDuck
public class ToyDuck extends Duck{public ToyDuck(String n){this.name =n;}
}
  • 接口FlyBehavior
public interface FlyBehavior {public void fly();
}
  • 飞行实现类FlyNoWay
public class FlyNoWay implements FlyBehavior {public void fly() {System.out.println("这是个假的飞行方法,我根本不会飞");}
}
  • 飞行实现类FlyWithWings

public class FlyWithWings implements FlyBehavior{public void fly() {System.out.println("我用翅膀飞翔");}
}
  • 测试类
public class DuckTest {public static void main(String[] args) {Duck toyDuck = new ToyDuck("Tim--ToyDuck");toyDuck.setFlyBehavior(new FlyNoWay());toyDuck.getName();toyDuck.myFlyBehavior();Duck mallardDuck = new MallardDuck("Jerry--mallardDuck");mallardDuck.setFlyBehavior(new FlyWithWings());mallardDuck.getName();mallardDuck.myFlyBehavior();}
}

测试结果:

this is Tim--ToyDuck
这是个假的飞行方法,我根本不会飞
this is Jerry--mallardDuck
我用翅膀飞翔

总结,再看实例

思路:分离变与不变。回忆之前的需求,可以发现,不变的是swim,变的是fly。虽然swim和fly都是鸭子的行为,但是swim不怎么变化,它可以利用继承来实现代码复用,而飞行方式却有很多种,无法继承,因此需要将飞行行为抽出来,各自实现,让Duck实现类拥有飞行行为实例,达到操作飞行行为的目的。这种思想就像零件的组装,主体是不变的,零件有各种相同功能不同性能的各种款式,这样可以做出不同的产品。
另外策略模式还有一个好处是可以动态变化行为,比如木头鸭子原来是不会飞的,它用setFlyBehavior设置不会飞行,后来设计师给他装上了引擎翅膀,它可以再次通过setFlyBehavior在运行时动态变更飞行行为。
说到这里,回顾之前写的策略模式(https://blog.csdn.net/u011109881/article/details/60478840)
在之前的例子中,看样子类图和本文的差很多,其实不然。我们对比一下:
Strategy就是本例中的FlyBehavior
Context就是本例中的Duck
之前的文章其实没有本文的类结构复杂,因为前文“只有一种鸭子”,因此也就省去“鸭子的各种实现类了”,所以看上去是比较简单的,但本质一样。另外,个人觉得之前的文章例子虽然可以解释策略模式,但是实际开发完全可以使用switch case来实现,因为那个例子没有明显的变与不变的地方。

其他策略模式的例子:

出行方式:比如一个角色character,他出门可以有不同的交通方式,如果目的地近,可以选择步行,如果距离远,可以选择开车,如果路上塞车,可以选择公交地铁。那么出行方式的变化可以抽出来形成一种策略。拿本文中的例子类比的话,角色相当于鸭子,各种交通方式相当于飞行行为。
游戏角色和武器装备:游戏中角色有不同的种类,战士法师弓箭手盗贼等等,角色可以穿着不同的武器装备,甚至还有角色限定,继续类比,则角色相当于不同种类的鸭子,武器套装则相当于不同的飞行方式,游戏角色可以随时更换武器装备。

Head First设计模式读书笔记一 策略模式相关推荐

  1. C++设计模式学习笔记:策略模式

    C++设计模式学习笔记:策略模式 策略模式设计商场促销 1.策略模式介绍 2.商场收银系统策略模式实现 3.策略模式与工厂模式结合 3.策略模式与工厂模式对比 策略模式设计商场促销 1.策略模式介绍 ...

  2. 设计模式读书笔记-----工厂方法模式

    一.问题 在前一章<设计模式读书笔记-----简单工厂模式>中通过披萨的实例介绍了简单工厂模式.在披萨实例中,如果我想根据地域的不同生产出不同口味的披萨,如纽约口味披萨,芝加哥口味披萨.如 ...

  3. 设计模式学习笔记--Strategy 策略模式

    所谓策略模式(Strategy Pattern),就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用:如果将策略.具体的算法和行为,编码在某个类或客户程序内部,将导至 ...

  4. 设计模式学习笔记(5) - 策略模式

    我一直觉得策略模式是一个很好玩的模式,让我们用游戏来了解一下. 举一个武侠的例子: 小说中大侠一般都有两样功夫: 第一:武功 第二:轻功 说到武功,让我们看看天龙八部里的三位高手的绝招: 萧峰:降龙十 ...

  5. Head First 设计模式学习笔记 一 策略模式

    策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. 这是一个比较简单的模式,核心的思想就是将应用中的变化之处独立出来,这样就可以 ...

  6. 大话设计模式读书笔记之原型模式

    由于大话这本书是以C#语言为基础写就的,本设计模式的例子中使用了一些c#中的API,因此就不再引用此书中的例子了,参考了一篇博客园中的大神写就的浅显易懂的JAVA版原型模式,在此奉上链接,以供大家学习 ...

  7. 大话设计模式读书笔记--4.代理模式

    生活中的例子: 班主任让班长通知班委下午3点开会 班长就是班主任的代理 代理模式的目的是: 隐藏真实访问对象,同时可以处理别的事情 定义 代理模式:为其他对象提供一种代理以控制对这个对象的访问 也就是 ...

  8. 大话设计模式读书笔记--6.原型模式

    简单的复制粘贴极有可能造成重复代码的灾难, 但是java中提供了克隆的功能, 如果一个对象创建过程复杂,又要频繁使用, 在初始化信息不发生变化的情况下,应当采取克隆而不是new一个对象 定义 原型模式 ...

  9. 大话设计模式读书笔记10----外观模式(Facade)

    外观模式(Facade):为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更容易使用. 1.在设计初级阶段,应该要有意识的将不同的两个层分离. 2.层与层之间建 ...

  10. 大话设计模式读书笔记之桥接模式

    1.定义: 将抽象部分与它的实现部分分离,使它们都可以独立地变化. 需要理解,什么叫抽象与它的实现分离,并不是说,让抽象类与其派生类分离,因为这没任何意义.实现指的是抽象类和它的派生类用来实现自己的对 ...

最新文章

  1. Spring.NET 1.3.1 新特性探索系列1——ASP.NET MVC的依赖注入
  2. [diary]极度自恋?
  3. python的2种字符串格式化输出
  4. 微信小程序|开发实战篇之七-steps进度条组件
  5. rails使用html form,Rails 页面多选下拉框, form_for, form_tag 使用技巧及 select2 使用
  6. 边缘计算的前景和挑战
  7. 直播视频网站源码,列表的展开更多和点击收起功能
  8. 基于巴法云平台的天猫精灵控制开关
  9. Treap树应用-bzoj 1862 GameZ游戏排名系统问题
  10. 详解RS485电路,就是那么简单!
  11. OSChina 周三乱弹 ——你是有多寂寞啊,看光头强都……
  12. 全国建筑模架业内人士齐聚联筑赚 携手并进同发展
  13. No.8 Sequence Median
  14. 【鸡头?凤尾?】选择大公司还是小公司是个问题
  15. OUTPUT 在insnert delete update 的神奇功效
  16. IP 地址的A B C类划分、区别
  17. Java Swing(九):弹出窗口
  18. FDTD add语句部分详细内容
  19. 免费域名注册-(Free domains for all)
  20. 简单的查找与排序的算法实现(python)

热门文章

  1. 慕课软件质量保证与测试(习题集)
  2. (七)视频背景移除/去背景/换背景/抠图/抠像代码示例:实时抠图、实时抠像、人像去背景、背景消除
  3. 货币转换python代码_[Python3 练习] 003 货币转换
  4. eslint / prettier 检查格式配置、husky / lint-staged 强制校验、tslint 配置
  5. vue项目前端页面模板,基于vue的前端模板
  6. HFSS天线设计笔记-------主极化与交叉极化
  7. keil 之Vscode编辑器插件、格式化代码插件和最新注册机分享
  8. 【加密工具】2019年网络安全加密工具排行,好用的计算机加密软件推荐
  9. 交通信息工程 实验四:交通仿真实验(二)
  10. dda算法_计算机图形学中的DDA(数字差分分析仪)算法