设计模式之策略模式
情景:
要设计很多鸭子,每个鸭子都有quack(呱呱叫)和swim功能。
可以设计一个Duck类,含有quack()和swim()方法就可以了。具体鸭子类继承Duck类。
新需求:要求添加fly功能。
如果直接给Duck添加fly()方法,会出现问题,因为有一部分鸭子是不会飞的。
选择创建Flyable接口,只有会飞的鸭子才继承接口,可以解决这一问题,但是造成代码无法复用。
设计原则:封装变化
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
因为鸭子的行为是变化的所以把鸭子的行为封装起来,创建一组行为类。
设计原则:针对接口编程,而不是针对实现编程。
针对接口编程的意思是: Animal animal = new Dog(); 而不是 Dog dog = new Dog();
Animal可以是超类或者接口,主要是通过多态,使得代码容易被扩展。
为每个行为写一个接口,行为的具体实现就是接口的一个实现类。这样具体行为就可以容易的被修改。
行为接口:
public interface FlyBehavior { public void fly(); } ----------- public interface QuackBehavior { void quack(); }
实现行为的具体类:
public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("I can't fly"); } } …………………… public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("I'm flying!"); } } …………………… public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("Quack"); } } …………………… public class MuteQuack implements QuackBehavior { @Override public void quack() { System.out.println("<< Silence >>"); } }
Duck超类:
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { }public void performFly() { flyBehavior.fly(); // 委托给行为类 } public void performQuack() { quackBehavior.quack(); } public void swim() { System.out.println("All ducks flost, even decoys!"); } public void display() { System.out.println("I am a duck."); } }
Duck一个具体实现类:
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display() { System.out.println("I'm a real Mallard duck."); } }
测试类:
public class MiniDuckSimulator { public static void main(String[] args) { Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly(); } }
输出:
Quack
I'm flying!
如果能在Duck类中通过setter动态设置行为,而不是只能在构造方法中绑定,就可以更灵活的改变鸭子的行为。
Duck类:
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { } public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } //...... }
新建一个模型鸭类型,默认不会飞
public class ModelDuck extends Duck { public ModelDuck() { flyBehavior = new FlyNoWay(); quackBehavior = new Quack(); } public void display() { System.out.println("I am a model duck."); } }
然后建立一个火箭动力类(???)
public class FlyRocketPowered implements FlyBehavior { @Override public void fly() { System.out.println("I am flying with a rocket."); } }
通过动态改变行为,模型鸭就可以飞啦~~
public class MiniDuckSimulator { public static void main(String[] args) { Duck model = new ModelDuck(); model.performFly(); model.setFlyBehavior(new FlyRocketPowered()); model.performFly(); } }
输出:
I can't fly I am flying with a rocket.
把鸭子的行为封装起来,这样可以自由的改变鸭子的行为,也方便对行为的扩展。
把行为改变为算法,就是策略模式。
设计原则:多用组合,少用继承。
策略模式:定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于算法的客户。
类图:
(讲道理我觉得书上这个例子举得一点都不好。。。。)
一个简单的例子:
public interface Strategy { public int doOperator(int num1, int num2); } …………………… public class AddStrategy implements Strategy { @Override public int doOperator(int num1, int num2) { return num1 + num2; } } …………………… public class SubStrategy implements Strategy { @Override public int doOperator(int num1, int num2) { return num1 - num2; } } …………………… public class MulStrategy implements Strategy { @Override public int doOperator(int num1, int num2) { return num1 * num2; } } …………………… public class Context { Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } public int doOperator(int num1, int num2) { return strategy.doOperator(num1, num2); } }
测试类:
public class Main { public static void main(String[] args) { Context context = new Context(new AddStrategy()); System.out.println(context.doOperator(2, 3)); context.setStrategy(new SubStrategy()); System.out.println(context.doOperator(2, 3)); context.setStrategy(new MulStrategy()); System.out.println(context.doOperator(2, 3)); } } /* Output: 5 -1 6 */