1.定义
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立与使用算法的客户。
2.案例分析
我们以一个案例为开始,我们有一个模拟鸭子游戏:SimUDuck,游戏中可能会有很多的鸭子,我们设计如下图所示的结构。
假设现在有一个橡皮鸭子RubberDuck,让其继承Duck类,那么问题来了,橡皮鸭子会集成Duck类的fly方法,显然橡皮鸭是不会飞的,虽然我们可以覆盖RubberDuck类中的fly方法让其什么都不做,但是如果有很多类似于橡皮鸭的其它鸭中,这将造成代码的冗余和不简洁。
所以我们换一种设计结构,将fly和quack设计成接口,即
这样设计会出现另外一个问题,如果有许多Duck的子类的都要修改fly方法,那么工作量将是巨大的,以为我们没有做到代码的复用。
继承会让子类拥有不需要的方法,接口又无法达到代码的复用。
设计原则:找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
这个例子中,Duck类是相对不变的,变化的是fly和quack,所以我们修改设计结构如下:
设计原则:针对接口编程,而不是针对实现编程。
简单来说就是
FlyBehavior fly = new FlywithWings();
而不是
FlywithWings fly = new FlywithWings();
鸭子现在会将飞行和呱呱叫的动作“委托”别人处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行算法。
3.具体实现
Duck类
package sxd.learn.dp;
public abstract class Duck {
protected FlyBehavior flyBehavior;
protected QuackBehavior quackBehavior;
public void setFlyBehavior(FlyBehavior fb){
this.flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb){
this.quackBehavior = qb;
}
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
public void swim(){
System.out.println("All duck float,even decoys");
}
}
package sxd.learn.dp;
public class MallardDuck extends Duck{
public MallardDuck(){
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("I'm a real mallard duck!");
}
}
FlyBehavior接口
package sxd.learn.dp;
public interface FlyBehavior {
public void fly();
}
package sxd.learn.dp;
public class FlyNoWay implements FlyBehavior{
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("I can't fly!!");
}
}
package sxd.learn.dp;
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("I'm flying!!");
}
}
QuackBehavior 接口
package sxd.learn.dp;
public interface QuackBehavior {
public void quack();
}
package sxd.learn.dp;
public class Quack implements QuackBehavior{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("Quack");
}
}
package sxd.learn.dp;
public class squeak implements QuackBehavior{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("Squeak");
}
}
package sxd.learn.dp;
public class MuteQuack implements QuackBehavior{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("Slience");
}
}
测试分析类
package sxd.learn.dp;
public class DuckSimulator {
public static void main(String[] args){
Duck mallard = new MallardDuck();
mallard.performFly();
mallard.performQuack();
System.out.println("dynamic change behavior");
mallard.setFlyBehavior(new FlyNoWay());
mallard.setQuackBehavior(new MuteQuack());
mallard.performFly();
mallard.performQuack();
}
}
测试结果
4.总结
“有一个”可能比“是一个”更好:每个鸭子都有一个FlyBehavion和一个QuackBehavior,而不是每个鸭子是一个…..。
当我们将两个类结合起来使用,这就是组合。
设计原则:多用组合,少用集成。