设计模式第一集——策略模式

  《Head First——设计模式》真是一本太太太好的书了!!!之前一看设计模式就头疼,这本书浅显易懂越看越想看。

  首先,设计模式第一集——策略模式:定义算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

  定义不好理解,举一个例子。

  假如现在要做一个模拟鸭子游戏,里面有各类鸭子。游戏中有各类鸭子,一边游泳(swim)一边嘎嘎叫(quack)。现在需要对原有的游戏代码进行改进,要求:

  1.在新增的游戏中,有些鸭子会飞;

  2.鸭子嘎嘎叫的方式有很多不同,比如有的吱吱叫;

  3.有一种模型鸭,可以动态的改变自己飞行行为(比如具备火箭动力飞行能力)

  针对上面的需求,很容易想到的是设计一个抽象的Duck类,该类里有swim、quack、fly等方法,其它类型的鸭子继承Duck类。这就是我完全不知道设计模式的时候想到的方法,这样设计有很多问题!比如:把fly的方法写到基类中,所有的类型鸭子继承之后都有了fly的能力,但是有些鸭子是不能飞的,就需要把这些鸭子的fly方法覆盖掉,n多个不能飞的鸭子就要覆盖n此,重复代码太多。同理,要求鸭子的嘎嘎叫法也不同,像之前的设计对于很多种鸭子都要重写它们的quack方法。

  那要怎么做?

  原则一:封装变化

  quack和fly的特性是不同鸭子有不同的方式,把他们从Duck的基类中拿出来,单独封装起来,建立一个新类来代表每一行为。这样对quack和fly方法的改变不会影响到其它部分。

  那怎么实现多种fly方式和quack方式呢?

  原则二:针对接口编程,而不针对实现编程

  这个很容易,分别写一个FlyBehavior和QuackBehavior的接口。具体想怎么飞怎么叫,在具体实现中去编吧。在Duck的基类中把之前写死的fly()和quack()方法去掉,改变成委托给FlyBehavior的引用

  public class FlyWithWings implments FlyBehavior{

        public void fly(){

             System.out.println("用翅膀飞!");

         }

    }

    public abstract class Duck{

       FlyBehavior flyBehavior;

   QuackBehavior quackBehavior;

       public void swim(){……}

       public void performFly(){ flyBehavior.fly();}//委托给飞的行为类实现飞的动作

       public void performQuack(){quackBehavior.quack();}

   }

    最后一个需求很简单,我们要动态的改变鸭子的行为,那在Duck中对鸭子的个个行为设立set()方法,当想让这个鸭子有哪种行为时,set一下就可以了。

  在最后还要提到一个原则三:多用组合,少用继承.FlyBehavior和QuackBehavior从之前的超类中拿出来,以组合的方式完成动作。

  鸭子游戏UML图:

  抽象的Duck类:

 1 package com.duck;
 2 
 3 public abstract class Duck {
 4     FlyBehavior flyBehavior;
 5     QuackBehavior quackBehavior;
 6     
 7     public abstract void display();
 8     
 9     //将飞、呱呱叫的行为委托给行为类
10     public void performfly(){
11         flyBehavior.fly();
12     }
13     public void performQuack(){
14         quackBehavior.quack();
15     }
16     public void quackBehavior(){
17         quackBehavior.quack();
18     }
19     
20     public void swim(){
21         System.out.println("I am swimming");
22     }
23     //动态设定行为
24     public void setFlyBehavior(FlyBehavior fb){
25         flyBehavior=fb;
26     }
27     public void setQuackBehavior(QuackBehavior qb){
28         quackBehavior=qb;
29     }
30 }

  FlyBehavior接口:

 1 package com.duck;
 2 
 3 public interface FlyBehavior {
 4     public void fly();
 5 }
 6 
 7 package com.duck;
 8 
 9 public class FlyNoWay implements FlyBehavior{
10     public void fly() {
11     }
12 
13 }
14 
15 package com.duck;
16 
17 public class FlyWithWings implements FlyBehavior{
18 
19     @Override
20     public void fly() {
21         System.out.println("I am flying");
22     }
23 }

QuackBehavior:

 1 package com.duck;
 2 
 3 public interface QuackBehavior {
 4     public void quack();
 5 }
 6 
 7 package com.duck;
 8 
 9 public class Quack implements QuackBehavior{
10 
11     public void quack() {
12         System.out.println("Quack");
13     }
14 
15 }
16 
17 package com.duck;
18 
19 public class Squeak implements QuackBehavior{
20 
21     public void quack() {
22         System.out.println("Squeak");
23         
24     }
25 
26 }

 要实现一个具体的绿头鸭:

现在嘎嘎叫的行为和飞的行为都是单独的类,这样对以后新增的鸭子可以直接组合想要的行为。将需要新的嘎嘎叫和飞行为的时候,写新的类实现实现。若有其他新的行为产生是,再写新的接口用和新的类具体实现。这样在代码维护的时候不用反复修改代码。

 1 package com.duck;
 2 
 3 public class MallardDuck extends Duck{
 4     
 5     public MallardDuck() {
 6         //绿头鸭的特点是可以呱呱叫和飞行
 7         //因为MallardDuck 继承自 Duck所以它具有quackBehavior和flybehavior实例变量
 8         quackBehavior=new Quack();//呱呱叫
 9         flyBehavior=new FlyWithWings();//
10     }
11 
12     @Override
13     public void display() {
14         System.out.println("I am a real Mallard duck");
15     }
16 }
原文地址:https://www.cnblogs.com/doublesong/p/2613608.html