Head First 设计模式(一)策略模式

计划三个月学完《Head First 设计模式》这本书(3月—5月),并记下笔记。
从这篇开始,希望自己最后能够坚持。好的,让我们开始吧~

第一篇学习的是策略模式

定义

首先抛出它的定义:

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

看到这个定义基本我们都是懵逼的,按照我的理解,翻译成人话就是:

将一个类中经常变化的部分(例如子类覆盖父类的方法)抽离出来,封装成单独的类,然后运用组合的思想,设定为类的成员变量。这样就可以动态的改变该类的行为了(只用改变类的成员变量)

什么,人话说的还是不清楚?嗯嗯,很正常,因为我们没有结合例子。

举例

下面我们结合一种实际应用场景来分析。

某公司开发了一个鸭子游戏,里面会出现各种特点的鸭子:绿头鸭,红头鸭,橡皮鸭……用程序如何实现这些鸭子?

看到这个场景问题,很容易想到,先定义一个所有鸭子的超类Duck,把公共方法和属性封装进去。例如,鸭子都会游泳,鸭子都有各自的外貌:

public abstract class Duck {

    public void swim(){
        System.out.println("All duck can swim!");
    }

    public abstract void display();

    public void fly(){
        System.out.println("飞~~~");
    }

    public void quack(){
        System.out.println("呱呱呱~");
    }

}

但是很快,我们发现这个超类的定义有问题。不是所有鸭子都会飞,不是所有鸭子都是呱呱叫(假设橡皮鸭是吱吱叫)。只要继承了这个超类,那所有的鸭子都会飞了,所有的鸭子都是呱呱叫了。

怎么办呢?

第一种解决方法

第一个想到的解决方法是:子类进行方法覆盖。很简单,不会飞的子类覆盖fly方法,重写不就行了?
但是,弊端很明显,所有不会飞的子类岂不都是要覆盖,假设50种鸭子都不会飞,那重写的工作量和维护量得有多大?

第二种解决方法

好的,所以我们想到第二个方法:继续设计子抽象类,例如会飞不会叫的抽象子类FlyNoQuackDuck,会叫不会非的抽象子类QuackNoFlyDuck,不会叫不会飞的抽象子类NoQuackNoFlyDuck,又会飞又会叫的抽象子类FlyAndQuackDuck……

写着写着我们发现这种方法也不行,太不灵活,而且改变的部分越多,这种抽象子类得定义的越多。

第三种解决方法

那什么方法才好呢?我们思考,之所以出现上面的问题,是因为我们习惯性的总想用继承来实现改变的部分,实际我们可以将改变的部分抽离出来,用组合来实现。

这里用到了三个设计原则:

  1. 找出应用中可能需要变化之处,把他们独立出来。
  2. 针对接口编程,而不是针对实现
  3. 多用组合,少用继承

运用第一个设计原则,我们将改变的方法fly()quack()独立出来,封装成两个行为类接口。然后根据不同的需求,设计出实现接口的不同行为类。

这里写图片描述

运用第二个和第三个设计原则,我们在Duck类中组合两个成员变量的接口,在子类中动态的赋值。

这里写图片描述

整体的“类图”如下:

这里写图片描述

总结:

    这种解决方法很完美的解决了我们的问题,运用”策略模式”的思想,将变化的部分抽离出来,组合进类中,根据不同的子类,可以“set”不同的行为子类进行,实现动态改变行为

代码

两个行为接口类:

public interface FlyBehavior {
    public void fly();
}

public interface QuackBehavior {
    public void quack();
}

实现飞行接口的不同行为类:


public class FlyNoWay implements FlyBehavior{

    public void fly(){
        System.out.println("我不能飞……");
    }
}


public class FlyWithWings implements FlyBehavior{

    public void fly(){
        System.out.println("飞~~~");
    }
}


public class FlyWithRocket implements FlyBehavior{

    public void fly(){
        System.out.println("带上火箭筒,飞~~~");
    }
}

实现鸭叫的不同行为类:


public class Quack implements QuackBehavior{
    public void quack(){
        System.out.println("呱呱呱~");
    }
}


public class Squeak implements QuackBehavior{
    public void quack(){
        System.out.println("吱吱吱~");
    }
}


public class MuteQuack implements QuackBehavior{
    public void quack(){
        System.out.println("我不会叫……");
    }
}

组合了实现接口的超类:

public abstract class Duck {
    protected FlyBehavior flyBehavior;
    protected QuackBehavior quackBehavior;

    public void swim(){
        System.out.println("All duck can swim!");
    }

    public abstract void display();

    /**
     * 动态改变飞行行为
     */
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    /**
     * 动态改变鸭叫行为
     */
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

    public void performFly(){
        flyBehavior.fly();
    }

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

不同的鸭子类:


/**
 * 绿头鸭
 */
public class MallarDuck extends Duck{

    public MallarDuck() {
        //可飞
        flyBehavior = new FlyWithWings();
        //呱呱叫
        quackBehavior = new Quack();
    }

    @Override
    public void display() {
        System.out.println("看着像绿头鸭");
    }

}


/**
 * 绿头鸭
 */
public class RedHeadDuck extends Duck{

    public RedHeadDuck() {
        //可飞
        flyBehavior = new FlyWithWings();
        //呱呱叫
        quackBehavior = new Quack();
    }

    @Override
    public void display() {
        System.out.println("看着像红头鸭");
    }

}


/**
 * 橡皮鸭
 */
public class RubberDuck extends Duck{

    public RubberDuck() {
        //不会飞
        flyBehavior = new FlyNoWay();
        //吱吱叫
        quackBehavior = new Squeak();
    }

    @Override
    public void display() {
        System.out.println("看着像橡皮鸭");
    }

}

测试类:


public class Main {

    public static void main(String[] args) {
        Duck mallarDuck = new MallarDuck();
        Duck redHeadDuck = new RedHeadDuck();
        Duck rubberDuck = new RubberDuck();

        mallarDuck.display();
        mallarDuck.performFly();
        mallarDuck.performQuack();
        System.out.println("========================");
        redHeadDuck.display();
        redHeadDuck.performFly();
        redHeadDuck.performQuack();
        System.out.println("========================");
        rubberDuck.display();
        rubberDuck.performFly();
        rubberDuck.performQuack();
        //改变行为特点
        rubberDuck.setFlyBehavior(new FlyWithRocket());
        rubberDuck.setQuackBehavior(new MuteQuack());
        rubberDuck.performFly();
        rubberDuck.performQuack();
    }
}/**output:
看着像绿头鸭
飞~~~
呱呱呱~
========================
看着像红头鸭
飞~~~
呱呱呱~
========================
看着像橡皮鸭
我不能飞……
吱吱吱~
带上火箭筒,飞~~~
我不会叫……
*/

猜你喜欢

转载自blog.csdn.net/z55887/article/details/60608898
今日推荐