上节我们谈到做一个鸭子的游戏,把共有的方法(游泳)作为父类,有变化的行为(飞,叫)作为接口,进而实现,满足各类鸭子去使用,那那我们该如何将它组合起来呢?
首先,在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.为了让某种行为可以出现多种变化,或者多种方式,以属性注入接口,可以动态控制
策略模式:定义了算法(行为),分别封装起来,让你过他们之间可以相互转换,此模式让算法的变化独立于使用算法的客户。(摘自设计模式)