第二篇:策略模式
来源:互联网 发布:华为笔试java 编辑:程序博客网 时间:2024/06/03 19:56
场景:你的公司最近要做一个飞机模型展览项目,该项目可以向客户展示各种各样的飞机,项目第一期可以确定的是这些飞机都有不同的外观,都可以发出声波,都可以飞行;好了,现在我们就知道这些,让我们开干吧!
(你该不会去纠结模型展览的飞机为什么会发声波还会飞行吧?...)
首先,用OO思维,我们可以先总结出一个父类:
/**所有飞机模型的父类*/public abstract class Flyable {/**发声波...*/protected void voice(){System.out.println("嗡...嗡...嗡...");}protected void fly(){System.out.println("我先直线加速...");System.out.println("我再拉起操纵杆...");System.out.println("然后...飞呀飞呀 我的骄傲放纵...");}/**子类必须自己去绘制自己的外观*/protected abstract void facade();}
接下来让我们创造两架飞机:
/**一架喷气机*/class GasPlane extends Flyable{@Overrideprotected void facade() {System.out.println("我是一家绿绿的喷气机");}}
/**一架客运机*/class GuestPlane extends Flyable{@Overrideprotected void facade() {System.out.println("白白的长长的...");}}
好啦,现在看起来一切都那么的完美,两架飞机只需要简单的绘制自己的外观,至于飞行和声波的功能,父类都给我们啦!瞧,代码多省事儿!
过了一个礼拜...新的需求还需要加入一架直升机,你马上开始写代码!
/**一架直升机*/class CopterPlane extends Flyable{@Overrideprotected void facade() {System.out.println("很炫的迷彩...");}/**注意,这里必须覆盖父类的飞行方法,因为直升机是螺旋桨飞行,不是跑道提速...*/@Overrideprotected void fly() {System.out.println("我先启动引擎");System.out.println("然后我再让我的小翅膀转呀转...");System.out.println("飞呀飞呀...");}}
又过了几天...需求还要加入一个木头做的模型飞机!”
...刷刷刷...代码写好了...”
class WoodPlane extends Flyable{@Overrideprotected void facade() {System.out.println("红色的木...");}}
这个代码有问题吗??当然有!木头做的模型机是不能飞的!但是它通过继承了Flyable,却拥有了飞行的能力!OK,那赶紧改代码吧!
class WoodPlane extends Flyable{@Overrideprotected void facade() {System.out.println("红色的木...");}/**注意:这里覆盖父类的飞行方法,并且什么都不做,因为木头模型飞机不能飞! * 我们不去关注木头飞机不能发出声波这个问题,如果关注这个点,后面我将要写更多的类...*/@Overrideprotected void fly() {}}好了,是时候说点什么了!你看出这个设计有什么问题了吗???没有的话我来给你讲讲吧!
首先,父类拥有飞行方法,所有的子类理论上都应该能飞行,但是,我们看到,直升机完全覆盖父类的方法,虽然在使用这个类的客户端看来它应该是像父类所描述的那样,在跑道加速,然后拉起操纵杆,然后起飞...但它实际上却完全不是这样走的。然后,我们的WoodPlane模型飞机看起来是能够飞的,但它实际上却直接覆盖父类方法,从而使自己失去飞行能力,这在使用这个类的人看来是很诡异的;
好吧,那我们怎么来改进这个程序的设计呢?要不,既然飞行方法会随着子类的变化而一直变,有的会飞有的还不会飞,那我们就设计一个接口,如果会飞的就实现这个接口,否则就不实现,这样对客户端来说不就一目了然了吗?
注:接口就是用来规划和描述一个对象应该会具有怎样的能力!面向对象设计原则,依赖抽象(接口或抽象类),不依赖具体实现;
如果用接口设计的话,又有什么问题呢?好吧,首先,我们得把父类Flyable的fly()方法去掉,这样所有子类都失去了飞行的能力,然后让我们的“喷气机”,“客运机”,“直升机” 分别去实现我们的接口,而“木头模型机”因为不具备飞行的能力,所以不去实现该接口;但是!问题来了,我们的喷气机辉和客运机它们的飞行方法都是一致的...或者说后期我们还要加入各种各样的飞机,它们的飞行方法都是一致的,但是呢!他们却都要去实现飞行方法,造成我们的代码不能复用!多处复制黏贴!!!
那我们有什么办法既能将飞行方法分离出来,又能让代码复用呢???当当当当!策略模式闪亮登场!
策略模式核心:将会变化的部分抽取出来,这些部分我们可以看成是一个行为,比如飞行就是一个行为 ,抽取出来后形成一个个的策略对象,所有需要的能力都委托给策略对象去执行!
在这里,我们会变得地方是fly()飞行方法,那么OK,进行代码改造吧!
首先,增加一个策略接口,它表示具有飞行这个行为,再造几个拥有不同飞行方式的策略类;
/**飞行行为接口*/interface FlyBehavioer{void fly();}/**拥有直线跑道加速...这种飞行能力的类*/class LineFlyBehavioer implements FlyBehavioer{@Overridepublic void fly() {System.out.println("我先直线加速....");System.out.println("我再拉起操纵杆...");System.out.println("然后...飞呀飞呀 我的骄傲放纵...");}}/**拥有螺旋桨盘旋飞行...这种飞行能力的类*/class CircleFlyBehavioer implements FlyBehavioer{@Overridepublic void fly() {System.out.println("我先启动引擎");System.out.println("然后我再让我的小翅膀转呀转...");System.out.println("飞呀飞呀...");}}/**不会飞的...所以是一个空实现,什么都不做*/class NonFlyBehavioer implements FlyBehavioer{@Overridepublic void fly() {}}
然后,改造我们的Flyable父类
public abstract class Flyable {//依赖于抽象protected FlyBehavioer flyBehavioer;//默认是不具备飞行能力的public Flyable() {this(new NonFlyBehavioer());}public Flyable( FlyBehavioer flyBehavioer ) {this.flyBehavioer = flyBehavioer;}protected void voice(){System.out.println("嗡...嗡...嗡...");}/**注意,这里委托给策略类去进行具体的飞行实现*/protected void toFly(){flyBehavioer.fly();}protected abstract void facade();/**可以在运行时动态改变飞行行为*/public void setFlyBehavioer( FlyBehavioer flyBehavioer ){this.flyBehavioer = flyBehavioer;}}
然后对我们的“喷气机”,“客运机”,"直升机","木头模型机" 进行改造:
/**一架喷气机*/class GasPlane extends Flyable{public GasPlane() {//初始化具备直线飞行能力super( new LineFlyBehavioer() );}@Overrideprotected void facade() {System.out.println("我是一家绿绿的喷气机");}}/**一架客运机*/class GuestPlane extends Flyable{public GuestPlane() {//初始化具备直线飞行能力super( new LineFlyBehavioer() );}@Overrideprotected void facade() {System.out.println("白白的长长的...");}}/**一架直升机*/class CopterPlane extends Flyable{public CopterPlane() {//初始化具备盘旋飞行能力super( new CircleFlyBehavioer() );}@Overrideprotected void facade() {System.out.println("很炫的迷彩...");}}//一架木头模型机class WoodPlane extends Flyable{@Overrideprotected void facade() {System.out.println("红色的木...");}}
public static void main(String[] args) {GasPlane gp = new GasPlane();gp.toFly();System.out.println("****************************");GuestPlane gtp = new GuestPlane();gtp.toFly();System.out.println("****************************");CopterPlane cp = new CopterPlane();cp.toFly();System.out.println("****************************");WoodPlane wp = new WoodPlane();wp.toFly();//让我们动态给木头飞机配上飞行的能力吧!System.out.println("****************************");wp.setFlyBehavioer(new CircleFlyBehavioer());wp.toFly();}
看下我们的输出结果!
我先直线加速....
我再拉起操纵杆...
然后...飞呀飞呀 我的骄傲放纵...
****************************
我先直线加速....
我再拉起操纵杆...
然后...飞呀飞呀 我的骄傲放纵...
****************************
我先启动引擎
然后我再让我的小翅膀转呀转...
飞呀飞呀...
****************************
为了看效果...我还是打印一下吧!我是飞不了的!!!
****************************
我先启动引擎
然后我再让我的小翅膀转呀转...
飞呀飞呀...
Ok,改造完成,让我们看看发生了什么变化!
我们增加了接口,增加了几个接口实现,然后所有飞机的飞行行为都委托给接口实现类去进行展示,这样有什么好处呢? 后期我们想要不同的飞行能力,只需要增加新的实现类就可以做到了!我们的”飞行“这个变化维度彻底与飞机解耦且可以进行代码复用,这对我们后期的扩展有非常大的帮助,我们想要改变飞行行为,压根就不需要去碰飞机实体了,因为你只需要执行setFlyBehavioer()就可以做到!虽然我们前期看似增加了代码量,但对于后期的维护与扩展来说,都是值得的!
最后,我们来看一下运用策略模式的类图;如果有疑问之处,给我留言喔!
- 第二篇:策略模式
- 第二章 策略模式
- 第二章 策略模式
- 第二层---策略模式
- 设计模式_第二篇_策略模式
- 【初探第二章】 策略模式
- 设计模式第二站--策略模式
- 设计模式第二章 策略模式
- 大话设计模式 第二章:策略模式
- 大话设计模式-第二章 策略模式
- 第二章 商场促销--策略模式
- 第二章 商品促销-策略模式(读书笔记)
- 第二章 商品促销---策略模式(读书笔记)
- 大话设计师 第二章 策略模式
- 大话设计模式 第二章 策略模式 C++实现
- 大话设计模式java版本 第二章 策略模式
- 大话设计模式-Study-Tips-第二章-策略模式
- 【读书笔记】大话设计模式 第二章 策略模式
- js正则校验方法
- UVa213-信息解码
- 连接池中的maxIdle,MaxActive,maxWait参数
- 网络中LAN、WAN、WLAN、VLAN和VPN的区别
- Android基础&进阶(收藏)
- 第二篇:策略模式
- mahout基于项目的协同过滤步骤
- JQuery笔记流
- 【Hibernate】初识了解
- 优化SQL的一般步骤
- let 命令 ---待更新
- WatcherWebService2
- redis优化配置
- CNN资料