[head first 设计模式] 第一章 策略模式

[head first 设计模式] 第一章 策略模式

让咱们先从一个简单的鸭子模拟器开始讲起。java

假设有个简单的鸭子模拟器,游戏中会出现各类鸭子,此系统的原始设计以下,设计了一个鸭子超类,并让各类鸭子继承此超类。算法

1.jpg

若此时咱们有了一个新的需求,咱们须要鸭子会飞,那么咱们该如何修改代码呢?编程

最初,咱们想在基类上加上fly方法,使得全部子类鸭子都拥有相应的fly方法。但这样错误产生了,即便是本不应会飞的橡皮鸭子也拥有了fly方法。设计模式

或许咱们能够把橡皮鸭中的fly方法覆盖掉,但这样每次新加入的不会飞的新鸭子类型,难道都要额外覆盖一次fly方法吗?太麻烦了。ide

利用继承来提供duck的行为,会致使运行时的行为不容易改变,且改变容易牵一发动全身。学习

那么,利用接口如何?this

若常常须要更新产品,那么每次覆盖fly简直是噩梦。那么,咱们将fly单独写成一个接口,只有会飞的鸭子实现这个接口如何?设计

2.jpg

但这样其实重复的代码会变得很是多,形成fly代码没法复用,每一个会飞的鸭子都要实现fly方法。3d

那么咱们该如何解决这个问题?在使用设计模式以前,不妨先求索于OO原则!code

软件开发中,什么是永恒真理?

惟一不变的是变化自己——约翰逊·斯宾塞

如今咱们已经知道了继承没法很好的解决问题,由于鸭子的行为在子类中不断改变,而且有的行为子类不该该拥有。使用接口初看挺不错的,但继承接口没法达到代码的复用。这意味着,不管合适你须要修改某个行为,你必须向下追踪并在每个定义此行为的类中修改它。

但还好,有一个OO设计原则正好适用于此种状况:

找出系统中可能须要变化之处,把他们独立出来,不要和那些不变化的代码堆在一块儿。

也就是把会变化的部分取出来,好让其余部分不会受此影响。

把会变化的部分取出来并封装,之后能够轻易地改动或扩充此部分,而不影响其余不须要变化的部分。

那么,如今是时候把鸭子的行为从Duck类中取出了。

分开变化和不会变化的部分

目前而言,除了fly()和quack()之外,duck类其余部分看起来不怎么变更,因此咱们仅作些小改变。

为此,咱们准备创建两组类,一个是和fly相关的,另外一个和quack相关的,每一组类都实现各自的动做。

3.jpg

设计鸭子的行为

如何设计

那组实现飞行和叫声的类呢?咱们但愿一切能有弹性,而且可以将行为指定到鸭子的实例。而且可让鸭子的行为动态的改变。

有了这些目标要实现,咱们看第二个设计原则

针对接口编程,而不是针对实现编程。

从如今开始,鸭子的行为将被放在分开的类中,此类专门提供某行为接口的实现。这样,鸭子类就再也不须要知道行为的具体细节。

此次鸭子类不会负责实现flying和quacking接口,而是由咱们制造一组其余类专门实现flybehavior和quackbeavior,这就称为行为类,由行为类而不是duck类来实现行为接口。

这种作法和以往不一样,以往是行为来自于duck超类的具体实现,或是继承某个接口并由子类自行实现而来。这两种方法都是依赖于实现,无法变动行为。

在咱们的新设计中,鸭子的子类将使用接口所表示的行为,因此具体的实现不会被绑定在鸭子的子类中。

4.jpg

整合鸭子的行为

关键在于,鸭子会将飞行和叫声行为委托给其余对象处理。而不是由本身定义。

在Duck类中加入flyBehavior和quackBehavior变量,声明为接口类型。每一个鸭子对象动态设置这些变量以在运行时引用正确的行为类型。

代码以下

public interface FlyBehavior {
    public void fly();
}
public interface QuackBehavior {
    public void quack();
}
public class FlyWithWings implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("I'm flying");
    }
}
public class FlyNoWay implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("I can't fly");
    }
}
public class Quack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("quack!");
    }
}
public class MuteQuack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("<<silence>>");
    }
}
public class Squeak implements QuackBehavior{

    @Override
    public void quack() {
        System.out.println("Squeak!");
    }
}
public abstract class Duck {
    protected FlyBehavior flyBehavior;
    protected  QuackBehavior quackBehavior;
    abstract void display();
    public void performFly()
    {
        flyBehavior.fly();
    }
    public void performQuack()
    {
        quackBehavior.quack();
    }
}
public class MallardDuck extends Duck{
    @Override
    public void display() {
        System.out.println("I'm a real mallard duck");
    }
    public MallardDuck(){
        flyBehavior = new FlyWithWings();
        quackBehavior  = new Quack();
    }
}
public class MiniDuckSimulator {
    public static void main(String[] args) {
        Duck mallardDuck = new MallardDuck();
        mallardDuck.performFly();
        mallardDuck.performQuack();
    }
}

动态设定行为

在鸭子子类中为两个behavior加入set方法,而不是在构造器中进行实例化。有了这个,咱们就能在运行时随时改变鸭子的行为。

public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

总体设计

如今咱们来看看总体结构

5.jpg

咱们再也不把鸭子的行为说成是行为,而是一族算法。算法表明鸭子能作的事情。在本例中,咱们鸭子的行为是组合来的,而不是继承来的。

咱们获得第三个OO设计原则

多用组合,少用继承

学习完以上部分,咱们正式定义策略模式

6.jpg

相关文章
相关标签/搜索