策略(strategy)模式
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)模式相关推荐
- 设计模式学习笔记——策略(Strategy)模式
设计模式学习笔记--策略(Strategy)模式 @(设计模式)[设计模式, 策略模式, Stategy] 设计模式学习笔记策略Strategy模式 基本介绍 策略案例 类图 实现代码 Hand类 S ...
- java语言商场打折_Java封装商场打折策略(Strategy模式)
有了OO的基础后,开始认真学习设计模式. 首先学习的是Strategy,下面就封装商场打折策略来分析下策略模式是怎样一回事. 商场每逢节假日都会对不同的商品采用不同的打折策略,首先卖苹果的说我的苹果要 ...
- java if打折怎么算_Java封装商场打折策略(Strategy模式)
有了OO的基础后,开始认真学习设计模式. 首先学习的是Strategy,下面就封装商场打折策略来分析下策略模式是怎样一回事. 商场每逢节假日都会对不同的商品采用不同的打折策略,首先卖苹果的说我的苹果要 ...
- 设计模式--策略(Strategy)模式
模式定义 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化),该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化) 类图 要点总结 Strategy及其子类为组件提供了 ...
- C++设计模式实现--策略(Strategy)模式
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/L_Andy/article/details/30489331 一. 举例说明 曾经做了一个程序,程序 ...
- 模板模式与策略模式/template模式与strategy模式/行为型模式
模板模式 模版模式,又被称为模版方法模式,它可以将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去 ...
- Strategy (策略)模式
10.1 策略模式 Strategy 的意思是 "策略",指的是与敌军对垒时行军作战的方法.在编程中,我们可以将其理解为 "算法". 无论什么程序,其目 ...
- 设计模式【14】——策略模式( Strategy 模式)
文章目录 前言 一.策略模式( Strategy 模式) 二.具体源码 1.Strategy.h 2.Strategy.cpp 3.Context.h 4.Context.cpp 5.main.cpp ...
- 策略模式(Strategy模式)
在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机.乘坐火车.骑自行车或自己开私家车等,超市促销可以釆用打折.送商品.送积分等方法. 在软件开发中也常常遇到类似的情 ...
最新文章
- python基础常用语句-Python语言的一些基本常用语句
- css margin和border,Margin、Border、Padding属性的区别和联系
- 实训总结_实训总结汇报!
- php speedtest,大神教你如何搭建自己的web speedtest站点
- 可以自发热的袜子,穿上暖3.9℃,这个冬天不再怕脚冷!
- 【Python】Could not find a version that satisfies the requirement cv2 (from versions: ) 的解决方案
- Finally it is here - Physbam source code has been released!
- 『Material Design 入门学习笔记』前言
- 手机通过WiFi控制电脑
- cesium相机控制
- vb.net html元素,vb.net 教程 12-3 HtmlElement类 1
- 使用Xshell重启远程服务器指令
- HTTP 出现304情况及详解
- elasticsearch ik分词--实现专有名词分词 同义词解析
- 【智能电视必装软件】小鲸电视、hdp直播国庆假期经典好剧随心看
- PTA1018 锤子剪刀布
- EF框架(一)搭建过程
- 【Docker】win7安装docker及镜像加速
- 企业微信可以取消实名认证吗?如何操作
- centos 自动化安装redis