策略模式
最近买了一本关于java设计模式的新书《Head First 设计模式》,里面介绍了java 的23种设计模式。目前看了第一章介绍的策略模式,里面的内容很容易理解,但是让我自己用嘴说出来却又总感觉表达不是很清楚。正所谓温故知新,所以我打算把自己的理解以及书上的代码记录到这里,算是一个回顾的过程。
策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
这本书上介绍策略模式使用的是一个鸭子的对象,其中鸭子有很多属性:飞行、鸣叫、展现形式等。由于要做一个通用的鸭子对象模型,所以我们需要把把这个鸭子创建成一个抽象的对象,将所有鸭子的通用属性放在抽象类中,而将差异化的属性在继承类中实现。考虑到代码的可扩展性和后期的维护,又将继承的这种模式进行改变,将两个类结合起来使用,即组合的方式。这种做法和继承不同的地方在于,鸭子的行为不是继承来的,而是和适当行为对象“组合”来的。使用组合建立系统具有很大的弹性,不仅可将算法族封装成类,更可以“在运行时动态地改变行为”,只要组合的行为对象符合正确的接口标准即可。
设计原则:多用组合,少用继承。
先来一张整体设计图:
这张图展示了利用策略模式对鸭子对象的属性进行拆分和组合,将鸭子的飞行和鸣叫的行为委托给接口来处理,而固定属性则封装在抽象类中。
上代码:
Duck类
package com.my.duck;FlyBehavior类
public abstract class Duck {
//为行为接口类型声明两个引用变量,所有鸭子子类都继承它们。
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck(){
}
public abstract void display();
public void performFly(){
flyBehavior.fly();//委托给行为类
}
public void performQuack(){
quackBehavior.quack();//委托给行为类
}
public void swim(){
System.out.println("All ducks float,even decoys!");
}
public void setFlyBehavior(FlyBehavior fb){//提供动态改变飞行行为的方法
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb){//提供动态改变鸣叫行为的方法
quackBehavior = qb;
}
}
package com.my.duck;FlyBehavior的实现
public interface FlyBehavior {
public void fly();//所有飞行行为类必须实现的接口
}
package com.my.duck;
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying !");
}
}
package com.my.duck;public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("I can't fly"); }}QuackBehavior接口
package com.my.duck;QuackBehavior实现
public interface QuackBehavior {
public void quack();
}
package com.my.duck;
public class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Quack");
}
}
package com.my.duck;public class MuteQuack implements QuackBehavior { @Override public void quack() { System.out.println("<<Silence>>"); }}
package com.my.duck;public class Squeak implements QuackBehavior { @Override public void quack() { System.out.println("Squeak"); }}
新建一个模型鸭子(ModelDuck)
package com.my.duck;运行函数:
public class ModelDuck extends Duck {
public ModelDuck(){
flyBehavior = new FlyNoWay();//一开始模型鸭子不会飞行
quackBehavior = new Quack();
}
@Override
public void display() {
System.out.println("I'm a model Duck");
}
}
package com.my.duck;运行效果:
public class MiniDuckSimulator {
public static void main(String[] args){
/*Duck mallard = new MallardDuck();
mallard.performFly();
mallard.performQuack();*/
Duck model = new ModelDuck();
//第一次调用performFly()会被委托给flyBehavior对象(也就是FlyNoWay实例),该对象是在模型鸭构造器中设置的。
model.performFly();
//这会调用继承来的setter方法,把火箭动力飞行的行为设定到模型鸭子中。
model.setFlyBehavior(new FlyRocketPowered());
//鸭子的飞行方式将变成乘坐火箭飞行器飞行。
model.performFly();
}
}