关于java:策略模式Strategy-Pattern封装变化灵活应对需求变更

5次阅读

共计 3453 个字符,预计需要花费 9 分钟才能阅读完成。

GitHub 源码分享

微信搜寻:码农 StayUp
主页地址:https://gozhuyinglong.github.io
源码分享:https://github.com/gozhuyinglong/blog-demos

1. 一个简略的模仿鸭子游戏

咱们先来看一个模仿鸭子的游戏:游戏中会呈现各种鸭子,它们一边游泳戏水,一边呱呱叫。

通过一番调研后:
已知的鸭子品种有:野鸭(Mallard Duck)、红头鸭(Redhead Duck)、橡皮鸭(Rubber Duck)。
已知的鸭子行为有:游泳(Swim)、嘎嘎叫(Quack)、显示鸭子的样子(Display)。

上面是这些鸭子的外观:

需要明确,开搞!

1.1 是时候展现 OO 技术了~

为了可复用性,设计了一个鸭子超类Duck,并让各种鸭子继承此超类:

  • 该超类中实现了 swim()quack() 办法,因为每一种鸭子外观不同,所以 display() 指定为形象办法(当然该类也是抽象类)。
  • 各个子类具体实现了 display() 办法
  • 因为橡皮鸭不会“嗄嗄叫”,所以重写了 quack() 办法为“吱吱叫”。

上面是 UML 类图:

1.2 Change!!!

咱们晓得软件开发的一个不变的真谛是:“变动”!

当初要求减少一种鸭子行为:航行(Fly),该怎么做呢?

如果持续应用继承,那么橡皮鸭是不会航行的,还是须要重写 fly() 办法。如下:

那如果再减少一种鸭子:钓饵鸭(Decoy Duck),这是只木头鸭子,它即不会叫,也不会航行 ……

看来继承是不能满足需要了!

1.3 应用接口怎么样?

fly() 办法和 quack() 抽离进去,做成接口,让领有该行为的鸭子对其进行实现。如下:

这仿佛解决了当初的问题!

但如果再减少 100 只鸭子呢?岂不是所有会航行或会叫的鸭子,都要实现一遍,没有达到代码的复用性。而且一旦要批改某个行为将是一件苦楚的事(比方将所有“吱吱叫”改成“仿真呱呱叫”)……

1.4 封装变动

有一个设计准则,恰好实用于下面模仿鸭子游戏的情况。

找出利用中可能须要变动之处,把它们独立进去,不要和那些不须要变动的代码混在一起。

换句话说,如果每次来新的需要,都会使某方面的代码发生变化,那么你就能够确定,这部分的代码须要被抽出来,和其余稳固的代码有所辨别。

这便是策略模式的精力所在,上面咱们来看该模式的具体介绍。

2. 策略模式

策略模式(Strategy Pattern)是一种行为型模式。该模式定义一系列的算法,把它们一个个封装起来,并使它们能够互相替换。该模式让算法的变动独立于应用它的客户。

Define a family of algorithms, encapsulate each one, and make them interchangeable.

该设计模式体现了几个设计准则:

  • 封装变动
  • 针对接口编程,而不是实现类
  • 多用组合,少用继承

策略模式由三局部组成:

  • Strategy(策略)

定义了所有策略的公共接口。上下文(Context)应用这个接口来调用某个具体策略(ConcreteStrategy)。

  • ConcreteStrategy(具体策略)

Strategy 接口的实现,定义了一个具体的策略实现。

  • Context(上下文)

定义了 Strategy 对象如何来应用,是策略算法的调用者。

3. 代码实现

咱们应用策略模式实现下面模仿鸭子游戏。

3.1 航行行为实现

定义航行行为接口

public interface Fly {void fly();
}

用翅膀航行实现类

public class FlyWithWings implements Fly {
    @Override
    public void fly() {System.out.println("用翅膀航行");
    }
}

不会航行实现类

public class FlyNoWay implements Fly {
    @Override
    public void fly() {System.out.println("不会航行");
    }
}

3.2 鸭叫行为实现

定义鸭叫行为接口

public interface Quack {void quack();
}

呱呱叫实现类

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

吱吱叫实现类

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

不会叫实现类

public class QuackNoWay implements Quack {
    @Override
    public void quack() {System.out.println("不会叫");
    }
}

3.3 鸭子类的实现

定义鸭子抽象类

public abstract class Duck {

    protected Fly fly;
    protected Quack quack;

    public void swim() {System.out.println("正在游泳...");
    }

    public abstract void display();

    public Fly getFly() {return fly;}

    public Quack getQuack() {return quack;}
}

野鸭实现类

public class MallardDuck extends Duck {

    // 野鸭用翅膀航行,呱呱叫
    public MallardDuck() {this.fly = new FlyWithWings();
        this.quack = new QuackGuaGua();}

    @Override
    public void display() {System.out.println("外观是绿头鸭");
    }
}

红头鸭实现类

public class RedheadDuck extends Duck {

    // 红头鸭用翅膀航行,呱呱叫
    public RedheadDuck() {this.fly = new FlyWithWings();
        this.quack = new QuackGuaGua();}

    @Override
    public void display() {System.out.println("外观是红头鸭");
    }
}

橡皮鸭实现类

public class RubberDuck extends Duck {

    // 橡皮鸭不会航行,吱吱叫
    public RubberDuck() {this.fly = new FlyNoWay();
        this.quack = new QuackZhiZhi();}

    @Override
    public void display() {System.out.println("外观是橡皮鸭");
    }
}

钓饵鸭实现类

public class DecoyDuck extends Duck {

    // 钓饵鸭不会航行,也不会叫
    public DecoyDuck() {this.fly = new FlyNoWay();
        this.quack = new QuackNoWay();}

    @Override
    public void display() {System.out.println("外观是钓饵鸭");
    }
}

3.4 测试

编写简略测试类

public class Test {public static void main(String[] args) {MallardDuck mallardDuck = new MallardDuck();
        mallardDuck.display();
        mallardDuck.swim();
        mallardDuck.getFly().fly();
        mallardDuck.getQuack().quack();

        System.out.println("-------------------");

        DecoyDuck decoyDuck = new DecoyDuck();
        decoyDuck.display();
        decoyDuck.swim();
        decoyDuck.getFly().fly();
        decoyDuck.getQuack().quack();
    }
}

输入后果

外观是绿头鸭
正在游泳...
用翅膀航行
呱呱叫
-------------------
外观是钓饵鸭
正在游泳...
不会航行
不会叫

4. 残缺代码

残缺代码请拜访我的 Github,若对你有帮忙,欢送给个 Star,谢谢!

https://github.com/gozhuyingl…

5. 参考

  • 《Head First 设计模式》
  • 《设计模式:可复用面向对象软件的根底》

举荐浏览

  • 单例模式
正文完
 0