Head First一书中对于策略(strategy)模式的正式定义是:策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

为了介绍这个算法,书中讲了一个例子:

在某个游戏中,有各种各样的鸭子,系统的内部设计使用了严格的OO技术,设计了一个鸭子(Duck)父类,所有的鸭子种类均继承于此父类。Joe设计的鸭子类如下:

package com.first.strategy;public class Duck1 {public Duck1(){}//鸭子会游泳public void swim(){  }//鸭子会呱呱叫public void quack(){   }//鸭子会飞public void fly(){   }//描述不同的鸭子,子类继承时覆盖重写public void display(){   }
}

然后让各种鸭子都继承此类,并且重写display()方法,例如:

class DuckA extends Duck1
{public void display(){ System.out.println("I am DuckA!");}
}

这样的设计缺点显而易见:新加入的鸭子种类“橡皮鸭子”也能飞,且也能呱呱叫(橡皮鸭子不能飞也不能呱呱叫),这是违背现实的。因为所有的子类均会继承来自父类的fly()方法和quack()方法,所有的子类均具备了fly()和quack(),使得不适合子类的行为也继承了父类的行为。

这时,Joe又想到了继承,可以在子类橡皮鸭(RubberDuck)中覆盖父类的fly()和quack()方法,让其不能飞也不能呱呱叫。

package com.first.strategy;public class RubberDuck extends Duck1{@Overridepublic void quack() {// TODO Auto-generated method stubSystem.out.println("我不会呱呱叫,我会吱吱叫!");}@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("I can not fly!");}
}

这时缺点同样清楚:代码重复太多,每个子类全部要覆盖,代码的可重用性太低。

Joe想到了接口,即把Duck类中的fly和quack从父类中抽象出来,变成接口Flyable和Quackable,这样,只有会飞的鸭子子类才继承Flyable接口,只有会呱呱叫的鸭子继承Quackable接口。这也不是一个好主意,因为它的缺点同样显而易见:和上面重写覆盖类似,重复的代码太多,不易维护,要修改,子类全要修改。

既然继承并不能很好的解决这个鸭子问题,那么我们便寻求变化。鸭子的行为在子类中不断变化,并且让所有的鸭子都具有这些行为是不恰当的。Flyable和Quackable接口的想法开始不错,但是,Java接口中的方法不具有实现,所有子类继承接口无法达到代码复用的效果。这就意味着,无论何时要修改某个行为,那么必须向下追踪所有定了这个行为的类(或子类)中去修改。这时一个设计原则应运而生,恰好解决此问题:

设计原则1:找出应用中可能需要变化之处,把他们独立出来,不要把需要变化的代码和不变的代码混杂在一起。即:把会变化的的部分取出来封装起来,以便以后可以轻易的改动或扩充此部分,而不影响不会变化的部分。

现在就把变化的部分从Duck类中分离,变化的部分就是fly()和quack(),因为这两者会随着鸭子的不同而改变。我们分离出来的两个方法建立两个类,一个是与fly相关,一个与quack相关,每一组类实现各自的动作或行为。例如一个类实现“呱呱叫”,另外一个类实现“吱吱叫”,还有一个类实现“安静不叫”(例如木头鸭子)。这是运用了第二条原则:

设计原则2:针对接口编程,而不是实现。

所有的和fly相关的行为,组装成一个接口,quack接口类似。并且分别定义各种与之相关的行为。

package com.first.strategy;public interface FlyBehavior {public void fly();}
package com.first.strategy;public interface QuackBehavior {public void quack();
}

呱呱叫类:

package com.first.strategy;public class Quack implements QuackBehavior{@Overridepublic void quack() {// TODO Auto-generated method stub//呱呱System.out.println("quack..quack");}}

吱吱叫类:

package com.first.strategy;public class Squeak implements QuackBehavior{public void quack() {// TODO Auto-generated method stub//吱吱System.out.println("squeak..squeak");}
}
和fly相关的两个类:
<pre class="java" name="code"><pre class="java" name="code">package com.first.strategy;public class FlyNoWay implements FlyBehavior{@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("Can not fly!!");}}
package com.first.strategy;public class FlyWithWings implements FlyBehavior{@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("Flying with wings!");}}

这样一来,可以让飞行和呱呱叫的动作被其他的对象复用,因为这些行为被抽象出来,与鸭子类无关了。我们可以增加一些动作,既不会影响现有的行为类,也不会影响使用这些行为类的鸭子类。

现在要整合鸭子的行为:

1.在Duck中加入两个实例变量,分别是FlyBehavior的实例变量flybehavior和QuackBehavior的实例变量quackbehavior,为借口类型而不是具体的实现类型(为了使用多态)。同时将原Duck类中的fly()和quack()方法删除,加入两个相似的方法performFly()和performQuack()

package com.first.strategy;public abstract class Duck {FlyBehavior flybehavior;QuackBehavior quackbehavior;public Duck(){}public abstract void display();public void performFly(){flybehavior.fly();}public void performQuack(){quackbehavior.quack();}public void swim(){System.out.println("All ducks can swim!");}
}

2.Duck子类中对flybehavior和quackbehavior实例变量的设置:

package com.first.strategy;public class MallardDuck extends Duck{public MallardDuck(){flybehavior = new FlyWithWings();quackbehavior = new Squeak();}public void display(){System.out.println("I am a mallardDuck!");}
}
package com.first.strategy;public class RubberDuck extends Duck1{@Overridepublic void quack() {// TODO Auto-generated method stubSystem.out.println("我不会呱呱叫,我会吱吱叫!");}@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("I can not fly!");}
}
3.主测试用例
package com.first.strategy;public class Client {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubDuck mallardduck = new MallardDuck();mallardduck.display();mallardduck.performFly();mallardduck.performQuack();}}

4.运行程序。

动态设定行为

1.在鸭子里很多动态的功能没有用到,很可惜,我们可以在Duck类中增加setter方法来设置鸭子的行为,而不是在构造器中实例化:

package com.first.strategy;public abstract class Duck {FlyBehavior flybehavior;QuackBehavior quackbehavior;public Duck(){}public void setFlyBehavior(FlyBehavior flybehavior){this.flybehavior = flybehavior;}public void setQuackBehavior(QuackBehavior quackbehavior){this.quackbehavior = quackbehavior;}public abstract void display();public void performFly(){flybehavior.fly();}public void performQuack(){quackbehavior.quack();}public void swim(){System.out.println("All ducks can swim!");}
}

2.构造一个新的鸭子模型:模型鸭子(ModelDuck),这个鸭子开始不会飞。

package com.first.strategy;public class ModelDuck extends Duck{public MallardDuck(){flybehavior = new FlyNoWay();//不会飞quackbehavior = new Quack();}public void display(){System.out.println("I am a ModelDuck!");}
}

3.建立新的FlyBehavior类型

package com.first.strategy;public class FlyRocketPowered implements FlyBehavior{@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("I can fly with a rocket!");}}

4.主测试类:

package com.first.strategy;public class Client {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubDuck modelduck = new ModelDuck();modelduck.performFly();//开始不会飞modelduck.setFlyBehavior(new FlyRocketPowered());modelduck.performFly();//现在会飞了}}

鸭子和FlyBehavior和QuackBehavior是“HAS—A”关系,两个类组合起来(composition),鸭子的行为不是继承来的,而是组合而来。这里是第三个设计原则:

原则3:多用组合,少用继承。

使用组合组建系统具有很大的弹性,不仅可将算法族封装成类,更可以在运行时动态的改变行为。

转载于:https://www.cnblogs.com/sunp823/p/5601416.html

策略(strategy)模式相关推荐

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

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

  2. java语言商场打折_Java封装商场打折策略(Strategy模式)

    有了OO的基础后,开始认真学习设计模式. 首先学习的是Strategy,下面就封装商场打折策略来分析下策略模式是怎样一回事. 商场每逢节假日都会对不同的商品采用不同的打折策略,首先卖苹果的说我的苹果要 ...

  3. java if打折怎么算_Java封装商场打折策略(Strategy模式)

    有了OO的基础后,开始认真学习设计模式. 首先学习的是Strategy,下面就封装商场打折策略来分析下策略模式是怎样一回事. 商场每逢节假日都会对不同的商品采用不同的打折策略,首先卖苹果的说我的苹果要 ...

  4. 设计模式--策略(Strategy)模式

    模式定义 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化),该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化) 类图 要点总结 Strategy及其子类为组件提供了 ...

  5. C++设计模式实现--策略(Strategy)模式

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/L_Andy/article/details/30489331 一. 举例说明 曾经做了一个程序,程序 ...

  6. 模板模式与策略模式/template模式与strategy模式/行为型模式

    模板模式 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...

  7. Strategy (策略)模式

    10.1 策略模式   Strategy 的意思是 "策略",指的是与敌军对垒时行军作战的方法.在编程中,我们可以将其理解为 "算法".   无论什么程序,其目 ...

  8. 设计模式【14】——策略模式( Strategy 模式)

    文章目录 前言 一.策略模式( Strategy 模式) 二.具体源码 1.Strategy.h 2.Strategy.cpp 3.Context.h 4.Context.cpp 5.main.cpp ...

  9. 策略模式(Strategy模式)

    在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机.乘坐火车.骑自行车或自己开私家车等,超市促销可以釆用打折.送商品.送积分等方法. 在软件开发中也常常遇到类似的情 ...

最新文章

  1. python基础常用语句-Python语言的一些基本常用语句
  2. css margin和border,Margin、Border、Padding属性的区别和联系
  3. 实训总结_实训总结汇报!
  4. php speedtest,大神教你如何搭建自己的web speedtest站点
  5. 可以自发热的袜子,穿上暖3.9℃,这个冬天不再怕脚冷!
  6. 【Python】Could not find a version that satisfies the requirement cv2 (from versions: ) 的解决方案
  7. Finally it is here - Physbam source code has been released!
  8. 『Material Design 入门学习笔记』前言
  9. 手机通过WiFi控制电脑
  10. cesium相机控制
  11. vb.net html元素,vb.net 教程 12-3 HtmlElement类 1
  12. 使用Xshell重启远程服务器指令
  13. HTTP 出现304情况及详解
  14. elasticsearch ik分词--实现专有名词分词 同义词解析
  15. 【智能电视必装软件】小鲸电视、hdp直播国庆假期经典好剧随心看
  16. PTA1018 锤子剪刀布
  17. EF框架(一)搭建过程
  18. 【Docker】win7安装docker及镜像加速
  19. 企业微信可以取消实名认证吗?如何操作
  20. centos 自动化安装redis

热门文章

  1. 再见,2014;您好,2015!
  2. 如何书写高质量的jQuery代码
  3. 4款语音播报来电短信应用[Android]
  4. Solr的自动完成实现方式(第三部分:Suggester方式续)
  5. founder of girton college
  6. fly a kite
  7. 烧水壶起水沟了怎么办?
  8. 13.3的MacBook air 8g内存还是有点吃力
  9. spring boot actuator服务监控与管理
  10. mysql varchar 225 和 varchar 60 区别