行为型模式之策略模式

概述

一般的,当我们需要实现某个可能存在「未完待续」,也就是更多的「模型」之时,一定会导致我们的代码造成极大的耦合。如,我们在玩「植物大战僵尸」的游戏。一般最基础的僵尸如下图所示。
1.png

我们可以得知,僵尸具备四中行为,即:外观、移动方式、攻击方式。很显然,如果我们需要设计这样一个模型,按照昨天学习的模板方法模式的理解,我们可以直接创建一个「僵尸抽象类」,将三种方式以抽象方法的形式实现,不过我们可以以「普通僵尸」提供一个默认的实现,这样以增加复用性。

那么,如果我们现在需要添加一个「大头僵尸」,就是直接继承与「僵尸抽象类」然后直接实现「攻击方式」,将其实现成「头撞」就好了。

那么问题来了,如果未来的某一天被提出增加一个「大大头僵尸」,它的技能也是「头撞」呢?好,你可以直接继承于「大头僵尸」,然后再重写它的独特实现即可。

那么... 如果又有一个基于「大大头僵尸」僵尸的呢... 好吧,继续继承.. 这样的代码结构,相信你已经看出来了,当业务日渐增多,整个结构极其复杂,不管是对自己还是对别人,都是极其恶心的。

所以,我们就需要对其进行抽离,如何解决?这便是「策略模式」的应用场景。

整体

首先明确我们的任务,我们要将做到「抽离存在变化的状态的事物」。即,将上述的「外观、移动方式、攻击方式」三种状态抽离出来。

interface Attack{
    void attack();
}

interface Move{
    void move();
}
interface Display{
    void display();
}

当我们需要某种形式的状态时,去实现对应的接口。

class Bump implements Attack{
    @Override
    public void attack() {
        System.out.println("用头撞击的对方");
    }
}

然后我们去设计「僵尸类」。我们创建了两个构造方法,其中的无参数方法我们可以在其中编写默认的实现,即如果不自定义实现方式就使用默认的。

因此,当想要「增加新的僵尸」的时候,如果它的攻击形式、显示形式、移动形式之前已经实现了,我们就不需要再次实现

 class Zombie {
    private Attack attackable;
    private Move moveable;
    private Display displayable;

    public Zombie() {
        /**
         * 如果调用无参数构造方法,则提供默认实现。
         */
    }

    public Zombie(Attack attackable, Move moveable, Display display) {
        this.attackable = attackable;
        this.moveable = moveable;
        this.displayable = display;
    }

    public void attack() {
        attackable.attack();
    }

    public void move() {
        moveable.move();
    }

    public void dispaly() {
        displayable.display();
    }

}

当然,这个代码还有一定的优化空间,便不再撰述。