博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
策略模式
阅读量:4162 次
发布时间:2019-05-26

本文共 4390 字,大约阅读时间需要 14 分钟。

网址连接:

      前段时间买了一本书《Head First设计模式》,看了第一章后才对设计模式的概念有少许了解:它其实是开发过程中很多前人的经验与智慧的总结,帮助你在开发时采取更好的方式去设计各个类、方法、以及它们之间的调用、实现方式,让代码保持灵活性的同时又能更好地复用。基于学过一块知识一定要用文字记录、总结、巩固,而不是走马观花的原则,趁最近终于有空,特将前一段时间看的关于“策略模式”的内容总结于此。

场景描述

A公司要做一套模拟鸭子的游戏,游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫,还有一些会飞。

方案1 继承

设计一个超类Duck,包含方法quack()、swim()、fly()分别模拟鸭子的叫、游泳、飞行等行为,再包含一个抽象类display(),用于展示各个鸭子不同的外观,让每个鸭子子类继承父类时实现display()。

弊端:

这样做的好处是,每个鸭子子类继承父类时就同时拥有了父类的方法,可以达到代码复用的目的,但是这样会使某些并不适合该行为的子类也具有该行为。如果某些子类鸭子,如“橡皮鸭”,它不具备某些功能(如飞行),它就不应该拥有这个飞行的功能。当然,你可以在子类中通过@Override覆盖这个方法。但是当各个不同的子类都需要通过覆盖修改不同的方法时,就会非常繁琐,而且容易出现纰漏,且这些新覆盖的方法不能被复用。如“橡皮鸭”只会叫不会飞,“木头鸭”不会叫也不会飞。以后每当有新的鸭子子类出现,你都要去检查并可能需要覆盖这些方法,想想都让人抓狂。

方案2 接口

在超类Duck中将quack()、fly()等可变的方法用接口Quackable(),Flyable()来代替,然后在每个鸭子子类中,如果具有“飞行”或“叫”这个功能就实现“飞行“或”叫“这个接口。

弊端:

代码无法复用,如果有100个子类,都具有飞行的行为,你就需要重复100次代码。

设计模式来帮忙

设计原则一:找出程序中可能需要变化的地方和不需要变化的地方,将它们独立开来。让系统中的某部分改变不会影响其他部分。

由于fly()和quack()会随着鸭子的不同而改变,所以把这两个行为从Duck类中分开,建一组新类来代表各个行为。

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

利用多态,针对超类型编程,执行时根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。以前的做法是:行为来自超类的具体实现或是继承某个接口并由子类自行实现。这两种方法都捆绑于”实现“,无法方便地更改行为。现在我们利用接口代表每个行为,比如FlyBehavior,QuackBehavior,然后让各个行为类实现这些接口,然后在Duck类中只要定义这个接口的实例变量即可,这样在各个鸭子子类中如果想拥有某种特定的行为,只要用这个接口实例变量去引用具体的行为类即可。

设计原则三:多用组合,少用继承。

飞行和叫这两种不同的行为,我们分别为其建立两组不同的行为类,然后在Duck类中通过接口实例变量结合起来,这就是”组合“。使得系统具有很大的弹性,还可以”在运行时动态地改变行为“。

1.UML图:

下面就是经过重新设计后的应用代码:

2.接口FlyBehavior

 public interface FlyBehavior {     public void fly(); }

3.接口QuackBehavior 

public interface QuackBehavior {     public void quack(); }

4.Fly行为的一个实现——FlyNoWay 

public class FlyNoWay implements FlyBehavior{     @Override     public void fly() {         System.out.println("I can not fly.");     } }

5.Fly行为的另一个实现——FlyWithWings 

public class FlyWithWings implements FlyBehavior {     @Override     public void fly() {         System.out.println("I can fly!");     } }

6.Fly行为的又另一个实现——FlyRocketPowered  

public class FlyRocketPowered implements FlyBehavior{     @Override      public void fly() {         System.out.println("I am flying with a rocket.");     } }

7.父类Duck

 public abstract class Duck {     FlyBehavior flyBehavior;     QuackBehavior quackBehavior;     public abstract void display();     public void performFly(){         flyBehavior.fly();     }     public void performQuack(){         quackBehavior.quack();     }     public void setFlyBehavior(FlyBehavior fb){         this.flyBehavior = fb;     }     public void setQuackBehavior(QuackBehavior qb){         this.quackBehavior=qb;     } }

8.Duck的一个子类——绿头鸭MallardDuck 

public class MallardDuck extends Duck{     public MallardDuck() {         flyBehavior = new FlyWithWings();         quackBehavior = new QuackWithGuaGua();     }     @Override     public void display() {        System.out.println("I am a MallardDuck.");             } }

9.Duck的另一个子类——模型鸭ModelDuck 

public class ModelDuck extends Duck {     public ModelDuck() {         flyBehavior = new FlyNoWay();         quackBehavior = new QuackNoWay();     }         @Override     public void display() {         System.out.println("I am a ModelDuck.");            } }

10.应用模拟器(执行主类):MiniDuckSimulator 

public class MiniDuckSimulator {     public static void main(String[] args) {         Duck mallardDuck = new MallardDuck();         mallardDuck.display();         mallardDuck.performFly()         mallardDuck.performQuack();         Duck modelDuck = new ModelDuck();         modelDuck.display();         modelDuck.performFly();         modelDuck.performQuack();         modelDuck.setFlyBehavior(new FlyRocketPowered());         modelDuck.performFly();     } }

执行代码,得到的结果如下:

总结

      策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。这是书里给出的策略模式的定义,依我个人的理解,这种模式的关键就是要将系统中的可变行为抽象出来,单独进行封装,用一组行为类(算法族)来实现该特定的接口,这样任何类(如Duck)如果想拥有这些算法族中的某个算法,都可以通过定义接口实例变量而拥有该整个算法族,在子类中再对该变量进行赋值。

      像这个例子里,通过定义了FlyBehavior,这样以后任何想有飞行行为的类如飞机,都可以调用这个接口及实现它的各个飞行类。且飞行行为的变化可以通过增加新的飞行类来实现,不会对其他部分(如quack()、display()等行为,亦或是已拥有某些特定飞行行为的对象)造成任何影响,即”算法的变化独立于使用算法的客户“。而且各个飞行行为之间也可以互相替换。即 setFlyBehavior(Flybehavior fb)。

      可见,设计模式的应用让整个项目的代码拥有了极大的灵活性,且达到了代码复用的效果。设计模式其实是一种设计上的思维方式,是前人的智慧和经验的总结,其真正的精髓不是看过就能学会的,还是需要在实际应用中不断地实践摸索,慢慢体会

分析:策略模式和桥接模式区别

(1)策略模式和桥接模式经过学习发现,都是将一个事物的抽象和它的实现分离开来,使其两者具有一定的独立扩展的可能性,但是两者有什么区别呢?

(2)桥接模式强调接口仅提供基本操作,而这些基本操作定义更高层次的操作,内部可以独立扩展,可不属于一个整体;策略模式强调抽象接口提供的是一种算法,Context简单调用这些算法完成操作;

  参考 桥接模式:

(3)桥接模式通过继承、聚合的方式组合类和对象形成更大的结构;而策略模式则通过接口之间的协作完成不同功能的组合,是一种行为模式(重点理解)

(4)桥接模式要表达的内容比较多,结构也比较复杂,其实是接口隔离的原则,本质上把布局类的两种体系区别开来,使得他们可以松散的组合,而策略模式在解耦只是某一个算法级别的层次。客观上讲:策略模式只是桥接模式的 一部分;

 

转载地址:http://ecxxi.baihongyu.com/

你可能感兴趣的文章
C 语言 学习---回调、时间定时更新程序
查看>>
对话周鸿袆:从程序员创业谈起
查看>>
Mysql中下划线问题
查看>>
Xcode 11 报错,提示libstdc++.6 缺失,解决方案
查看>>
vue项目打包后无法运行报错空白页面
查看>>
阿里p8程序员四年提交6000次代码的确有功,但一次错误让人唏嘘!
查看>>
一道技术问题引起的遐想,最后得出结论技术的本质是多么的朴实!
查看>>
985硕士:非科班自学编程感觉还不如培训班出来的,硕士白读了?
查看>>
码农:和产品对一天需求,产品经理的需求是对完了,可我代码呢?
查看>>
第六章 背包问题——01背包
查看>>
1136 . 欧拉函数
查看>>
面试题:强制类型转换
查看>>
Decorator模式
查看>>
Template模式
查看>>
Observer模式
查看>>
高性能服务器设计
查看>>
图文介绍openLDAP在windows上的安装配置
查看>>
Pentaho BI开源报表系统
查看>>
Pentaho 开发: 在eclipse中构建Pentaho BI Server工程
查看>>
JSP的内置对象及方法
查看>>