常用设计模式之策略模式

初始需求

一款模拟鸭子的游戏,涉及到如下几个类:

/**
 * 鸭子抽象类
 */
public abstract class Duck {
    /**
     * 嘎嘎叫
     */
    public void quack() {
        System.out.println("嘎嘎叫");
    }
    /**
     * 游泳
     */
    public void swim() {
        System.out.println("游泳");
    }
    /**
     * 外观
     */
    public abstract void display();
}
/**
 * 绿头鸭
 */
public class MallardDuck extends Duck {
    @Override
    public void display() {
        System.out.println("绿头");
    }
}
/**
 * 红头鸭
 */
public class RedHeadDuck extends Duck {
    @Override
    public void display() {
        System.out.println("红头");
    }
}
/**
 * 橡皮鸭
 */
public class RubberDuck extends Duck {
    /**
     * 橡皮鸭只会吱吱叫,故重写此方法
     */
    @Override
    public void quack() {
        System.out.println("吱吱叫");
    }
    @Override
    public void display() {
        System.out.println("橡皮");
    }
}

问题出现

现在要加个需求,让绿头鸭和红头鸭会飞。直接在Duck抽象类里加fly()方法,结果问题出现了:橡皮鸭居然飞起来了。显然不合理。于是想到一个解决办法,在橡皮鸭类中覆盖fly()方法,使它不会飞。可是如果后期又增加一个“诱饵鸭”(木头做的,不会飞也不会叫),又得覆盖quack()和fly()方法。这意味着,以后每增加一个鸭子类型,都得检查并可能覆盖quack()和fly()方法。

解决办法

将变化的部分取出并封装起来,对应这个案例中的quack()和fly()方法。于是代码变成这样:

/**
 * 鸭子抽象类
 */
public abstract class Duck {
    protected QuackBehavior quackBehavior;
    protected FlyBehavior flyBehavior;
    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }
    /**
     * 叫声行为
     */
    public void performQuack() {
        this.quackBehavior.quack();
    }
    /**
     * 飞行行为
     */
    public void performFly() {
        this.flyBehavior.fly();
    }
    /**
     * 游泳
     */
    public void swim() {
        System.out.println("游泳");
    }
    /**
     * 外观
     */
    public abstract void display();
}
/**
 * 飞行行为接口
 */
public interface FlyBehavior {
    void fly();
}
/**
 * 叫声行为接口
 */
public interface QuackBehavior {
    void quack();
}
public class FlyNoWay implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("不会飞");
    }
}
public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("用翅膀飞行");
    }
}
public class Quack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("嘎嘎叫");
    }
}
public class Squeak implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("吱吱叫");
    }
}
public class MuteQuack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("不会叫,是个哑巴");
    }
}
/**
 * 绿头鸭
 */
public class MallardDuck extends Duck {
    public MallardDuck() {
        this.quackBehavior = new Quack();
        this.flyBehavior = new FlyWithWings();
    }
    @Override
    public void display() {
        System.out.println("绿头");
    }
}
/**
 * 红头鸭
 */
public class RedHeadDuck extends Duck {
    public RedHeadDuck() {
        this.quackBehavior = new Quack();
        this.flyBehavior = new FlyWithWings();
    }
    @Override
    public void display() {
        System.out.println("红头");
    }
}
/**
 * 橡皮鸭
 */
public class RubberDuck extends Duck {
    public RubberDuck() {
        this.quackBehavior = new Squeak();
        this.flyBehavior = new FlyNoWay();
    }
    @Override
    public void display() {
        System.out.println("橡皮");
    }
}

应对不断变化的需求

现在,增加一个“诱饵鸭”,它不会飞也不会叫:

/**
 * 诱饵鸭
 */
public class DecoyDuck extends Duck {
    public DecoyDuck() {
        this.quackBehavior = new MuteQuack();
        this.flyBehavior = new FlyNoWay();
    }
    @Override
    public void display() {
        System.out.println("木头做的");
    }
}

然后又新增一个“模型鸭”,它一开始不会飞,只会叫:

/**
 * 模型鸭
 */
public class ModelDuck extends Duck {
    public ModelDuck() {
        this.quackBehavior = new Quack();
        this.flyBehavior = new FlyNoWay();
    }
    @Override
    public void display() {
        System.out.println("我是一个玩具模型");
    }
}

在游戏中,触发某个条件,比如捡到火箭助推器,模型鸭就会飞了:

public class FlyRocketPowered implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("使用火箭助推器");
    }
}

这里模拟调用的地方:

public static void main(String[] args) {
    Duck duck = new ModelDuck();
    duck.setFlyBehavior(new FlyRocketPowered());
    duck.performFly();
    duck.performQuack();
}

总结

重构后的代码可以动态的改变鸭子的飞行行为和叫声,如果把行为的实现绑死在鸭子类中,可就无法做到这样了。案例中飞行行为和叫声就是策略,不同的鸭子有不同的策略。
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值