策略模式

定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

  举一个简单的例子来描述策略模式。

  设计一款冷兵器时代士兵打仗的游戏,游戏内部设计要使用OO技术。

  首先,设计一个士兵对象(Soilder)作为父类,然后在设计许多不同种类的士兵对象来继承士兵这个父类,比如:长枪兵(Spearman)、骑兵(Cavalryman)、弓箭手(Bowman)等等,设计好后进行讨论,觉得不错没有问题,可以开始开发,测试,游戏公测……一切都不错,具体如下面的类图所示:

  

  在游戏运营了一段时候之后,发现需要一些新元素来吸引玩家,要求不同种类的士兵的攻击动作不同,并且要求士兵需要有游泳、攀爬等技能。使用OO技术非常好解决啊,打开类的设计图开始干活吧!可以把hit方法设计成抽象方法,让每种士兵都实现自己的hit,然后在Soilder类中加入游泳,攀爬的方法,修改的类图如下:

  

  使用这种设计方式后,在游戏运行的过程中我们会看到,骑兵骑着马在爬树。显然的,在设计的时候忽略了一点,并非所有的士兵都可以游泳和攀爬。有许多不可做这些行为的士兵,对代码的局部修改,影响的层面可不仅是局部。

  使用继承如何?

  把swim和clmb放到子类中,覆盖掉父类的对应方法,像hit的做法一样。可如果以后要加入其他类型的士兵又会如何?比如重甲步兵没办法游泳也没办法攀爬,因为重甲太重了,而骑兵则无法骑着马攀爬,但可以骑着马过河等等。可见利用继承来提供士兵的行为会造成:

  1.代码在多个子类中重复;

  2.运行时的行为不容易改变;

  3.很难知道所有士兵的全部行为;

  4.改变会牵一发而动全身,造成其他某些类型的士兵不想要的行为;

  利用接口如何?

  可以加入ISwin和IClimb接口,把swim函数和climb函数从父类中取出来,并被子类实现,如下图所示:

  

  但士兵的规格会常常改变,每当有新的士兵类型出现,就要被迫检查兵可能需要实现ISwim和IClimb接口。并且这么以来重复的代码会变多,因为实现的可以游泳和爬树的代码是一样的。比如有一天swim的方式发生了变化,现有的50个士兵子类都需要修改swim函数,这是不可以接受的。

  如何解决?

  可以看出,并非所有的子类都会游泳和爬树,所以继承并不是适当的解决方式。虽然使用接口可以解决一部分问题,但是却造成了代码无法复用,幸运的是,有一个原则恰好用于此处。

设计原则1

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

  也就是说,每次需求一来,都会使某些方面的代码发生变化,那么基本可以确定这部分代码需要被抽出来和其他稳定的代码有所区分。

  现在,为了要分开变化和不会变化的部分,我们准备建立两组类,一个是swim相关的,一个是clmb相关的,并且要做到一切能有弹性,正因为一开始设计的行为没有弹性才导致种种问题。比方说,我要产生一个新的类型的轻甲士兵,并指定行为攀爬给他,也就是说在士兵类中包涵设置行为的方法,这样就可以在运行时动态改变行为,有了这些目标要实现,就引出了第二个设计原则。

设计原则2

针对接口或抽象类编程,而不是针对实现编程。

  我们利用接口代表每个行为(Behavior),比方说SwimBehavior和ClimbBehavior,而行为的每个实现都将实现其中的一个接口。Soilder类不会负责实现它们,反而是由一组其他类专门去实现,并整合到Soilder类中,具体的做法是在Soilder类中加入两个实例变量,分别为SwimBehavior和ClimbBehavior,声明为接口类型,每个士兵子类都会动态的设置这些变量在运行时引用正确的行为类型。看一下类图与实现的代码(Java代码)。

  

  

package cn.net.bysoft.Strategy;//    士兵
public abstract class Soldier {//    士兵的名字private String name;private SwimBehavior swimBehavior;private ClimbBehavior climbBehavior;public Soldier() {super();}public Soldier(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public SwimBehavior getSwimBehavior() {return swimBehavior;}public void setSwimBehavior(SwimBehavior swimBehavior) {this.swimBehavior = swimBehavior;}public ClimbBehavior getClimbBehavior() {return climbBehavior;}public void setClimbBehavior(ClimbBehavior climbBehavior) {this.climbBehavior = climbBehavior;}//    显示士兵的信息public void display() {System.out.println("这个士兵的名字:" + name);}//    士兵攻击敌人。public abstract void hit();//    委托给行为去处理。public void swim() {swimBehavior.swim();}public void climb() {climbBehavior.climb();}
}

士兵类的代码

package cn.net.bysoft.Strategy;//    长枪兵
public class Spearman extends Soldier {public Spearman() {}public Spearman(String name) {super(name);}@Overridepublic void hit() {// TODO Auto-generated method stubSystem.out.println("士兵使用长枪去攻击敌人");}
}package cn.net.bysoft.Strategy;//    骑兵
public class Cavalryman extends Soldier {public Cavalryman() {}public Cavalryman(String name) {super(name);}@Overridepublic void hit() {// TODO Auto-generated method stubSystem.out.println("骑士在马上用刀攻击敌人");}
}package cn.net.bysoft.Strategy;//    弓箭手
public class Bowman extends Soldier {public Bowman() {}public Bowman(String name) {super(name);}@Overridepublic void hit() {// TODO Auto-generated method stubSystem.out.println("弓箭手拉弓瞄准射击敌人");}
}

长枪兵、骑士、弓箭手等士兵的代码

package cn.net.bysoft.Strategy;//    游泳行为的接口。
public interface SwimBehavior {//    只需在此定义一个游泳的行为方法即可。public void swim();
}package cn.net.bysoft.Strategy;//    不能游泳
public class SwimNoWay implements SwimBehavior {public void swim() {// TODO Auto-generated method stubSystem.out.println("这个士兵不能游泳");}}package cn.net.bysoft.Strategy;//    士兵自己游泳,不通过其他途径。
public class SwimWithBody implements SwimBehavior{public void swim() {// TODO Auto-generated method stubSystem.out.println("士兵自己游泳过河");}}package cn.net.bysoft.Strategy;//    士兵骑马游泳
public class SwimWithHouse implements SwimBehavior {public void swim() {// TODO Auto-generated method stubSystem.out.println("士兵骑马过河");}}

游泳行为接口与其实现类的代码

package cn.net.bysoft.Strategy;//    攀爬行为的接口
public interface ClimbBehavior {public void climb();
}package cn.net.bysoft.Strategy;public class ClimbNoWay implements ClimbBehavior {public void climb() {// TODO Auto-generated method stubSystem.out.println("这个士兵不能攀爬");}}package cn.net.bysoft.Strategy;//    士兵爬树。
public class ClimbTree implements ClimbBehavior {public void climb() {// TODO Auto-generated method stubSystem.out.println("士兵开始爬树");}}

攀爬行为接口与其实现类的代码

package cn.net.bysoft.Strategy;public class Game {public static void main(String[] args) {// TODO Auto-generated method stub//    一个玩家建立一个长矛兵进入游戏Soldier spearman = new Spearman("长矛高手");spearman.hit();//    设置这个士兵的行为,可以自己游泳,爬树。spearman.setSwimBehavior(new SwimWithBody());    spearman.setClimbBehavior(new ClimbTree());spearman.swim();spearman.climb();System.out.println(" ============================= ");//    另一个玩家建立士兵进入游戏Soldier cavalryman = new Cavalryman("圆桌骑士");cavalryman.hit();//    设置这个士兵的行为,可以骑马过河,但是不可以爬树。cavalryman.setSwimBehavior(new SwimWithHouse());cavalryman.setClimbBehavior(new ClimbNoWay());cavalryman.swim();cavalryman.climb();}
}

测试类,测试策略模式

  总结一下,请特别注意类之间的关系,关系可以是IS-A(是一个)也可以是HAS-A(有一个)或IMPLEMENTS(实现)。HAS-A关系相当有趣,每一个士兵都有SwimBehavior和ClimbBehavior的行为,并将这些动作交给它们去处理,当将两个类结合起来使用,就是这种组合。这种做法和继承不同的地方在于,行为不是继承来的,而是和适当的行为对象组合来的。这是一个很重要的技巧,骑士是使用了第三个设计原则:

设计原则3

多用组合,少用继承。

  使用组合建立系统具有很大的弹性,不仅可以将算法族封装成类,更可以在运行时动态地改变行为,只要组合的行为对象符合正确的接口标准即可。以上就是策略模式的介绍。

转载于:https://www.cnblogs.com/DeadGardens/p/5132116.html

[设计模式学习笔记] -- 策略模式相关推荐

  1. Java-马士兵设计模式学习笔记-策略模式-模拟Comparable接口

    一.情况 1.目标:要在专门用于排序数据的DataSorter.java中实现对所有A类,B类,C类,D类等等的排序 2.初步想法:DataSorter.java的代码如下 public class ...

  2. 设计模式学习笔记——策略(Strategy)模式

    设计模式学习笔记--策略(Strategy)模式 @(设计模式)[设计模式, 策略模式, Stategy] 设计模式学习笔记策略Strategy模式 基本介绍 策略案例 类图 实现代码 Hand类 S ...

  3. 设计模式 - 学习笔记 - 工厂模式Factory Pattern

    设计模式 - 学习笔记 - 工厂模式Factory Pattern 1. 简单工厂 1.1 应用场景 1.2 UML 1.3 优劣分析 好处 缺点 1.4 代码示例 抽象产品 AbstractProd ...

  4. 设计模式学习:策略模式

    策略模式简介 策略模式:策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现.策略模式最大的特点是行为的变化,行为之间可以相互替换.每个if判断都可以理解为就是 ...

  5. Head First设计模式读书笔记——策略模式

    问题描述: 目前的任务是实现一个FPS类游戏的各种角色(友军.敌军.平民和狗.猫.鸭子等动物)以及他们的各种行为(攻击.游泳等). 设计方案一 很简单,只要实现一个角色超类,将角色的各种行为放入超类中 ...

  6. 设计模式学习01策略模式记录

    (个人记录)策略模式带来的好处就是更加的有弹性,可以很方便的动态改变对象的行为,在已经固定的项目中如果要增加新的类型,在项目中我们要分析变化部分与不变部分. 将变化的部分(也就是策略算法)使用接口的方 ...

  7. 设计模式学习笔记——外观模式

    外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性. 这种模式涉及 ...

  8. 设计模式学习之策略模式(Strategy,行为型模式)(13)

    转载地址:http://www.cnblogs.com/zhili/p/StragetyPattern.html 一.引言 本文要介绍的策略模式也就是对策略进行抽象,策略的意思就是方法,所以也就是对方 ...

  9. 设计模式学习笔记-原型模式

    一.概述 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象: 二.模式中的角色 Prototype:声明一个克隆自身的接口: ConcretePrototype:实现一个克隆自身的操作: ...

最新文章

  1. 用java怎么开发图片标注工具_java 图片处理工具 测试
  2. 《强化学习周刊》第32期:上海交大华为 | 可解释强化学习研究综述
  3. POJ-3414 Pots BFS+记忆路径
  4. golang中的redigo
  5. WC2007 石头剪刀布 数学+最小费用最大流
  6. Android 5.0及以上实现屏幕截图
  7. V-Charts中使用extend属性定制词云图
  8. c# ef报错_C# EF调用MySql出现“未将对象引用设置到对象的实例”错误解决方案
  9. 计算机网络画出发送窗口变化,2010年7月计算机网络原理试题及答案
  10. java简单题目_Java考点知识简单练习题
  11. supervisor 子进程退出_用supervisor监管你的程序,不用担心程序挂了
  12. 02-橄榄球 VS 软件
  13. 地震及断层分析相关软件
  14. 用c语言写易语言Linux库,C语言编写支持库教程
  15. Excel VBA 巧用自定义函数进行数组去重
  16. 爬虫 - 股票爬虫实例之雪球网
  17. 常用的ADB命令有哪些
  18. stm32f107基本资料
  19. ESP32基于arduino开发的心跳体温检测系统(四)本地端系统整合
  20. 超级计算机 人脑,世界第4超级计算机竟被人脑秒成渣,人类的大脑究竟多厉害?...

热门文章

  1. win10 java模拟鼠标_[pc玩家]如何在Windows10中用键盘控制鼠标光标
  2. office启动出现oxc0000142的问题的解决方案
  3. con 元器件符号_关于元器件名称、符号和封装的命名问题
  4. 音乐家们的开源工具箱
  5. VCS仿真学习(5)Debugging with DVE
  6. 月星当空,月光洒落树梢透进窗户,白的苦楚,寥寂随之上心头
  7. SHA1WithRSA签名使用openssl 实现
  8. MyBatis超详细笔记
  9. VMware14虚拟机安装苹果系统
  10. iOS11.3 beta5专为提升苹果X速度?网友:iPhone6S的我们怎么办