Fork me on GitHub

《Head First 设计模式》之策略模式

前言

  昨晚lz在博客园里写了第一篇文章,虽然不是关于技术方面的,但终究算是正式开启了自己写作的生涯。曾经lz加入了一个微信群,是关于英语学习的。这个群里每天早上都会推送一条今日分享,其实就是一句中文和一句英文。当然这推送内容应该说是精挑细选的,会给人传递一些比较正能量的东西。lz觉得这种行为还是比较有意义的,所以,lz会在日后每条文章前面放上这些分享,希望能和广大友人共勉。

  最近,lz在学习设计模式,书籍为友人推荐的《Head First 设计模式》,心里有些体会,故将它写下来望能和大家共同交流和学习,写的不好还请大家多多见谅。今天给大家带来的是lz学完策略模式之后的感悟!

策略模式

  lz想摘录书中比较经典的话,使用模式最好的方式是:“把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。”以往是代码复用,现在是经验复用。

  先给出模拟鸭子这个应用的最终版本,其UML类图如下:

 上面这几个类,接口之间的关系还是很简单,相信大家都能看得懂哈!

   再给出具体的类,接口的示例代码如下

   封装飞行行为:

 1 package xin.yangmj.strategy.behavior.fly;
 2 
 3 /**
 4  * 这是飞行行为接口
 5  *
 6  * @author Eric Yang
 7  * @create 2017-10-06 下午1:31
 8  **/
 9 public interface FlyBehavior {
10     public void fly();
11 }

   具体的飞行行为实现类:

代表会飞的鸭子:

 1 package xin.yangmj.strategy.behavior.fly.impl;
 2 
 3 import xin.yangmj.strategy.behavior.fly.FlyBehavior;
 4 
 5 /**
 6  * 这是飞行行为得实现,给“真会”飞的鸭子用...
 7  *
 8  * @author Eric Yang
 9  * @create 2017-10-06 下午1:33
10  **/
11 public class FlyWithWings implements FlyBehavior {
12     public void fly() {
13         System.out.println("I'm flying!!!");
14     }
15 }

代表不会飞的鸭子:

 1 package xin.yangmj.strategy.behavior.fly.impl;
 2 
 3 import xin.yangmj.strategy.behavior.fly.FlyBehavior;
 4 
 5 /**
 6  * 这是飞行行为的实现,给“不会”飞的鸭子用...
 7  *
 8  * @author Eric Yang
 9  * @create 2017-10-06 下午1:36
10  **/
11 public class FlyNoWay implements FlyBehavior {
12     public void fly() {
13         System.out.println("I can't fly!!!");
14     }
15 }

拥有火箭动力的鸭子:

 1 package xin.yangmj.strategy.behavior.fly.impl;
 2 
 3 import xin.yangmj.strategy.behavior.fly.FlyBehavior;
 4 
 5 /**
 6  * 拥有火箭动力的飞行行为
 7  *
 8  * @author Eric Yang
 9  * @create 2017-10-06 下午2:16
10  **/
11 public class FlyRocketPowered implements FlyBehavior {
12     public void fly() {
13         System.out.println("I'm flying with a rocket!");
14     }
15 }

以上三个为具体的飞行行为实现类

针对鸭子叫的行为的不同,故也可以分为多种实现,如下;

首先封装呱呱叫行为,也即,抽象为超类

 1 package xin.yangmj.strategy.behavior.quack;
 2 
 3 /**
 4  * 这是叫的行为接口
 5  *
 6  * @author Eric Yang
 7  * @create 2017-10-06 下午1:40
 8  **/
 9 public interface QuackBehavior {
10     public void quack();
11 }

其次根据呱呱叫个区别有如下三个实现类

 1 package xin.yangmj.strategy.behavior.quack.impl;
 2 
 3 import xin.yangmj.strategy.behavior.quack.QuackBehavior;
 4 
 5 /**
 6  * 什么都不做
 7  *
 8  * @author Eric Yang
 9  * @create 2017-10-06 下午1:43
10  **/
11 public class MuteQuack implements QuackBehavior {
12     public void quack() {
13         System.out.println("<< Silence >>");
14     }
15 }
 1 package xin.yangmj.strategy.behavior.quack.impl;
 2 
 3 import xin.yangmj.strategy.behavior.quack.QuackBehavior;
 4 
 5 /**
 6  * 鸭子呱呱叫类
 7  *
 8  * @author Eric Yang
 9  * @create 2017-10-06 下午1:41
10  **/
11 public class Quack implements QuackBehavior {
12     public void quack() {
13         System.out.println("Quack");
14     }
15 }
 1 package xin.yangmj.strategy.behavior.quack.impl;
 2 
 3 import xin.yangmj.strategy.behavior.quack.QuackBehavior;
 4 
 5 /**
 6  * 橡皮鸭吱吱叫类
 7  *
 8  * @author Eric Yang
 9  * @create 2017-10-06 下午1:45
10  **/
11 public class Squeak implements QuackBehavior {
12     public void quack() {
13         System.out.println("Squeak");
14     }
15 }

 

现在给出鸭子超类:

 1 package xin.yangmj.strategy.duck;
 2 
 3 import xin.yangmj.strategy.behavior.fly.FlyBehavior;
 4 import xin.yangmj.strategy.behavior.quack.QuackBehavior;
 5 
 6 /**
 7  * 这是鸭子抽象类
 8  *
 9  * @author Eric Yang
10  * @create 2017-10-06 下午1:29
11  **/
12 public abstract class Duck {
13 
14     // 加上这两个public目的:Duck和其实现类不在同一包下,且Duck在外层包下
15     public FlyBehavior flyBehavior;
16     public QuackBehavior quackBehavior;
17 
18     public Duck(){}
19 
20     // 委托给行为类
21     public void performFly() {
22         flyBehavior.fly();
23     }
24     public void performQuack() {
25         quackBehavior.quack();
26     }
27 
28     // 所有鸭子共有的行为
29     public void swim() {
30         System.out.println("All ducks float, even decoys!");
31     }
32 
33     public abstract void display();
34 
35     // 动态设定行为
36     public void setFlyBehavior(FlyBehavior fb) {
37         flyBehavior = fb;
38     }
39     public void setQuackBehavior(QuackBehavior qb) {
40         quackBehavior = qb;
41     }
42 
43 }

 

再给出两个鸭子的具体实现类:

这是绿头鸭子

 1 package xin.yangmj.strategy.duck.impl;
 2 
 3 import xin.yangmj.strategy.behavior.fly.impl.FlyWithWings;
 4 import xin.yangmj.strategy.behavior.quack.impl.Quack;
 5 import xin.yangmj.strategy.duck.Duck;
 6 
 7 /**
 8  * 这是绿头鸭子
 9  *
10  * @author Eric Yang
11  * @create 2017-10-06 下午2:05
12  **/
13 public class MallardDuck extends Duck {
14 
15     public MallardDuck() {
16         flyBehavior = new FlyWithWings();
17         quackBehavior = new Quack();
18     }
19 
20     public void display() {
21         System.out.println("I'm a real Mallard duck!");
22     }
23 }

这是模型鸭子

 1 package xin.yangmj.strategy.duck.impl;
 2 
 3 import xin.yangmj.strategy.behavior.fly.impl.FlyNoWay;
 4 import xin.yangmj.strategy.behavior.quack.impl.Quack;
 5 import xin.yangmj.strategy.duck.Duck;
 6 
 7 /**
 8  * 模型鸭子
 9  *
10  * @author Eric Yang
11  * @create 2017-10-06 下午2:11
12  **/
13 public class ModelDuck extends Duck {
14 
15     public ModelDuck() {
16         flyBehavior = new FlyNoWay();
17         quackBehavior = new Quack();
18     }
19 
20     public void display() {
21         System.out.println("I'm a model duck!");
22     }
23 }

 

最后给出测试代码:

 1 package xin.yangmj.strategy;
 2 
 3 import xin.yangmj.strategy.behavior.fly.impl.FlyRocketPowered;
 4 import xin.yangmj.strategy.duck.Duck;
 5 import xin.yangmj.strategy.duck.impl.MallardDuck;
 6 import xin.yangmj.strategy.duck.impl.ModelDuck;
 7 
 8 /**
 9  * 这是整个策略模式的测试类
10  *
11  * @author Eric Yang
12  * @create 2017-10-06 下午2:33
13  **/
14 public class MiniDuckSimulator {
15     public static void main(String[] args) {
16         Duck mallard = new MallardDuck();
17         mallard.performFly();
18         mallard.performQuack();
19 
20         // 动态设定行为
21         Duck model = new ModelDuck();
22         model.performFly();
23         // 更改运行行为
24         model.setFlyBehavior(new FlyRocketPowered());
25         model.performFly();
26 
27         // 哈哈哈,这是测试Git
28     }
29 }

 

运行结果:

 

 

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

   通过上面的简单介绍可以总结出策略模式运用到的几个设计原则:

   1.找出应用中可能需要变化之处,把它们独立出来,不要和哪些不需要变化的代码混在一起。---封装变化,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分。在本例中,我们并没有将鸭子的两个行为fly()和quack()放到Duck类里面,这些行为会随着鸭子的不同而改变,让所有的子类都有这些行为是不恰当的,比如,某些鸭子可能不会飞等。所以,我们必须要将这两个行为从Duck类中分离出来,通过建立一组新类来代表每个行为,可以理解为定义中的算法族。这样的设计,可以让飞行和呱呱叫的动作行为被其他的对象复用,因为这些行为已经与鸭子类无关了,而我们也可以新增一些行为,不会影响到既有的行为类,也不会影响“使用”到飞行行为得鸭子类。这么一来,有了继承的“复用”好处,却没有继承所带来的包袱。

   2.针对接口编程,而不是针对实现编程。我们可以利用接口代表每个行为,比如说,FlyBehavior与QuackBehavior,而行为得每个实现都将实现其中的一个接口,这样一来,鸭子的子类将使用这两个行为接口所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类中,也即,鸭子类就不再需要知道行为的实现细节。

   3.多用组合,少用继承。“有一个”可能比“是一个”更好,本例中,每个鸭子都有飞和叫的行为,将这两个类结合起来使用,就是我们所说的组合。组合和“继承”的区别在于,鸭子的行为不是继承来的,而是和适当的行为对象“组合”来的。

 

 

 

posted @ 2017-10-06 16:47  萍韵众生  阅读(296)  评论(0编辑  收藏  举报