设计模式之策略模式------读书笔记

前言

在开发一个系统的过程中,我们可能会时不时的问自己,我们这么设计这块逻辑到底好不好,如果以后需要扩展这部分会不会很困难。有了这么多疑问,我们自然而然的就会想到去寻找问题的答案。幸运的是,Head First设计模式这本书为我们提供了很多问题的解答。我们要善于利用其它开发人员的经验与智慧,他们也曾遇到过相似的问题,也顺利解决过这些问题。这周,读了一下策略模式,读完之后,犹如醍醐灌顶。

鸭子的故事

策略模式是从简单的鸭子游戏开始讲起的。
众所周知,游戏中会出现各种鸭子,有的会游泳,有的会呱呱叫,有的会咕咕叫,有的会飞,有的不会飞。

我们最先想到的设计就是有一个鸭子的基类,这个基类中有quack()方法,swim()方法,display()(外观)方法。我们其他所有的鸭子都会继承这个基类。如下图:
在这里插入图片描述

注意1:因为每种鸭子的外观都不同,所以dispaly()方法是抽象的。
注意2:所有的鸭子都会呱呱叫(Quack),也会游泳(swim),所以由超类负责处理这部分的实现代码。
注意3:每个鸭子的子类负责实现自己的display()行为。

但是呢,公司想要为鸭子加上“会飞”这个方法。
我们首先想到的就是在鸭子的基类Duck上面再增加一个方法fly(),如下图所示:
在这里插入图片描述
然而,这样做出现了问题,我们忽略了一个事实就是“并不是所有的鸭子都会飞”,但是我们却在超类中增加了鸭子的“飞”的行为,这样会使得某也不适合该行为的子类也具有该行为。

当涉及“维护”时,为了使用“复用”(reuse)目的而使用继承,结局并不完美。

在这里插入图片描述
橡皮鸭不是呱呱叫,而是吱吱叫,所以我们在RubberDuck中讲quack()方法覆盖为吱吱叫,但是橡皮鸭不会飞,可能有人会想到,我们可以把橡皮鸭(RubberDuck)中的fly()方法覆盖掉,这样不就可以了?

可是,如果我们以后加入木头假鸭,这个又不会飞,也不会叫,这该怎么办呢?
在这里插入图片描述
我们有橡皮鸭,会叫但不会飞,我们还有木头假鸭,不会飞也不会叫,我们还有别的种类的鸭子,会飞也会叫。

利用接口如何

在这种情况下,有人可能会想到了使用接口,我们把fly()从超类中取出来,放进一个Flyable接口,只有会飞的鸭子才实现这个接口,同样的方式,我们也可以设计一个Quackable接口,只有会叫的鸭子才实现这个接口。

问题随之而来,虽然Flyable和Quackable可以解决一部分问题,但是却造成代码无法复用,这就像是从一个噩梦跳到另一个噩梦。甚至,在会飞的鸭子中,飞行的动作可能还有多种变化。

在这种情况下,我们接触到了第一个设计原则:

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

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

为了要分开“变化和不会变化的部分”,我们准备建立两组类(完全远离Duck类),一个是fly相关的,一个是quack相关的,每一组类将实现各自的动作。比方说,我们可能有一个类实现“呱呱叫”,另一个类实现“吱吱叫”,还有一个类实现“安静”。

设计鸭子的行为

我们希望一切能有弹性,毕竟,正式因为一开始鸭子行为没有弹性,才让我们走向现在这条路。我们还想能够“指定”行为到鸭子的实例。并指定特定“类型”的飞行行为给他。干脆顺便让鸭子的行为可以动态改变好了。

第二个设计原则:

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

我们利用接口代表每个行为,比方说,FlyBehavior 与QuackBehavior,而行为的每个实现都将实现其中的一个接口。

在这里插入图片描述
FlyBehavior是一个接口,所有的飞行类都实现它。
QuackBehavir是一个接口,代表叫的行为。

FlyWithWings是一个类,该类实现了FlyBehavior这个接口,代表所有有翅膀的鸭子飞行动作。
FlyNoWay是一个类,该类实现了FlyBehavior这个接口,代表所有不会飞的鸭子的动作。

同样,Quack Squeak MuteQuack也是三个类,分别实现了QuackBehavior这个接口,分别代表了鸭子呱呱叫、吱吱叫、安静行为。

这样的设计,可以让飞行和呱呱叫的动作被其他的对象复用,因为这些行为已经与鸭子类无关了。
而我们也可以新增一些行为,不会影响到既有的行为类,也不会影响“使用”到飞行行为的鸭子类。

整合鸭子的行为

关键在于,鸭子现在会将飞行和呱呱叫的动作“委托”(delegate)别人处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行方法。

Duck.java

public abstract class Duck {
    public void setFlyBehavior(FlyBehavior mFlyBehavior) {
        this.mFlyBehavior = mFlyBehavior;
    }

    FlyBehavior mFlyBehavior;

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

    QuackBehavior mQuackBehavior;

    public Duck(){

    }

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

    public void performQuack(){
        mQuackBehavior.quack();
    }
    public abstract void display();

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

FlyBehavior.java

public interface FlyBehavior {
    void fly();
}

FlyWithWings.java

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

FlyNoWay.java

public class FlyNoWay implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("I cannot fly");
    }
}

QuackBehavior.java

public interface QuackBehavior {
    void quack();
}

Quack.java

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

Squeak.java

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

MuteQuack.java

public class MuteQuack implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("<<Silence>>");
    }
}

定义好鸭子的基类和行为类之后,我们来创建我们的鸭子MallardDuck
MallardDuck.java

public class MallardDuck extends Duck {

    public MallardDuck(){
    }
    @Override
    public void display() {
        System.out.println("I am MallardDuck");
    }
}

以及我们的测试类MiniDuckSimulator.java

public class MiniDuckSimulator {
    public static void main(String [] args){
        Duck mallard = new MallardDuck();
        mallard.setFlyBehavior(new FlyWithWings());
        mallard.setQuackBehavior(new Quack());
        mallard.performFly();
        mallard.performQuack();
    }
}

运行代码:
在这里插入图片描述

总结

每一鸭子都有一个FlyBehavior和一个QuackBehavior,好将飞行和呱呱叫委托给他们代为处理。
当你将两个类结合起来使用,这就是组合(conposition),这种做法和继承的不同的地方在于,鸭子的行为不是继承而来的,而是组合而来的。

第三个设计原则:

多用组合,少用继承

经过很长的一段路,终于引出了我们的第一个设计模式:策略模式。

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

良好的OO设计必须具备可服用、可扩充、可维护三个特性。我们常常把系统中会变化的部分抽出来封装。有了策略模式,我们的系统不会担心遇到任何改变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值