上节我们谈到做一个鸭子的游戏,把共有的方法(游泳)作为父类,有变化的行为(飞,叫)作为接口,进而实现,满足各类鸭子去使用,那那我们该如何将它组合起来呢?
首先,在Duck 里面加入 FlyBehaviour 和 QuackBehaviour的实例变量,为接口类型,再添加可以执行的方法
performFly 和performQuack.
public class Duck { public FlyBehaviour flyBehaviour; public QuackBehaviour quackBehaviour; public void performFly(){ flyBehaviour.fly(); } public void performQuack(){ quackBehaviour.quack(); } public void swin(){ // 游泳 } }
下面我们看绿头鸭的类:
public class MallarDuck extends Duck{ public MallarDuck(){ // 这里用呱呱叫,可以飞 // 当perform 被调用时候,行为就委托给接口,我只需要得到叫或者飞的结果就行了 super.quackBehaviour = new QuackOne(); super.flyBehaviour = new FlyWithWing(); } public void display(){ // 绿头鸭 } }
这里我们发现,构造里面使用了new + 实现类,并且这里限定了绿头鸭叫的方式和飞的方式,也不灵活,
在原则中有一个是:针对接口编程(针对超类编程)
为了更加灵活,让我们的鸭子有更多的 叫的模式 和飞行模式。这样设计:
public class Duck { public FlyBehaviour flyBehaviour; public QuackBehaviour quackBehaviour; // 加入两个 设值方法,方便动态的改变行为方式 public void setFlyBehaviour(FlyBehaviour flyBehaviour) { this.flyBehaviour = flyBehaviour; } public void setQuackBehaviour(QuackBehaviour quackBehaviour) { this.quackBehaviour = quackBehaviour; } public void performFly(){ flyBehaviour.fly(); } public void performQuack(){ quackBehaviour.quack(); } public void swin(){ // 游泳 } }
上面类暂时不变,后面其他模式 代替这种写法。
现在假设 我们添加了一种新的飞行,NewFly.要求绿头鸭在特定情况下,可以使用新的模式
public class NewFly implements FlyBehaviour{ @Override public void fly() { // 这是一种新的飞行模式 System.out.println("fly 2"); } }
让我们进行测试:
public class Test { public static void main(String[] args) { Duck f1 = new MallarDuck(); f1.performFly(); // 换飞行模式 f1.setFlyBehaviour(new NewFly()); f1.performFly(); } }
现在已经可以随意的进行变化的,至于构造器那里,可以想想如何去完善。
小结 :我们这里分享思路:
1.将公共部分,放在超类里面使用
2.有变化的行为提炼成接口,提供实现类,提高代码的灵活性和复用性
3.所有的行为不用自己去实现,交给执行为的方法,我们只负责调用
4.为了让某种行为可以出现多种变化,或者多种方式,以属性注入接口,可以动态控制
策略模式:定义了算法(行为),分别封装起来,让你过他们之间可以相互转换,此模式让算法的变化独立于使用算法的客户。(摘自设计模式)