策略模式(strategy pattern)定义
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
分开变化和不会变化的部分
Duck类内的fly()和quack()行为会随着鸭子的不同而改变,属于变化的部分,将它们从Duck中抽取出来,建立一组新类代表每一种行为。
设计鸭子的行为
-
以往:行为来自于继承Duck超类的具体实现,或是继承某个接口后由子类自行实现而来。这两种方法都依赖于实现,没办法改变行为。
-
现在:Duck的子类将使用接口(
FlyBehavior
和QuackBehavior
)所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类中。 -
FlyBehavior
public interface FlyBehavior { abstract void fly(); }
-
QuackBehavior
public interface QuackBehavior { void quack(); }
实现鸭子的行为
-
我们已经有了2个行为接口(FlyBehavior和QuackBehavior),不同的Fly()和Quack()行为实现这两个接口。这样的好处就是fly()和Quack()与Duck无关了,我们可以新增一些行为,既不会影响到现有行为类,也不会影响使用这些行为的Duck子类。
-
FlyBehavior
各种各样的子类//拥有翅膀会飞翔 public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("使用翅膀飞翔了"); } } //不会飞翔的飞翔子类 public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("我不会飞翔"); } }
-
QuackBehavior
的各种子类//呱呱叫 public class Quack implements QuackBehavior{ @Override public void quack() { System.out.println("呱呱叫"); } } //吱吱叫 public class Squeak implements QuackBehavior{ @Override public void quack() { System.out.println("吱吱叫"); } } //不会叫 public class MuteQuack implements QuackBehavior { @Override public void quack() { System.out.println("不会叫"); } }
整合鸭子的行为
Duck会将飞翔和叫喊的动作委托别人处理,而不是使用定义在Duck类/子类中的飞翔和叫喊方法。
-
在Duck类中加入“两个实例变量”,flyBeahvior和QuackBehavior,声明为接口类型而不是具体的实现类,每个Duck实例都会动态的设置这些变量以运行时引用正确的行为类型。
FlyBehavior flyBehavior; QuackBehavior quackBehavior;
-
实现performFly和performQuack方法
public void performQuack() { flyBehavior.fly(); } public void performFly() { quackBehavior.quack(); }
更多的整合
如何设置FlyBehavior和QuackBehavior的实例变量?我们不在乎flyBehavior和quackBehavior引用的对象究竟是谁,我们只关心该对象知道自己正确的行为就可以了。
public class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("绿头鸭");
}
public MallardDuck() {
//初始化时指定MallardDuck正确的行为
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
}
动态设定行为
在Duck子类的构造方法中指定行为固然可行,可是一旦指定就不能更改了。怎么办?在Duck超类中增加set方法,动态指定fly和quack行为。
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
//测试类
ModelDuck modelDuck = new ModelDuck();
modelDuck.setFlyBehavior(new FlyRocketPowered());
modelDuck.setQuackBehavior(new MuteQuack());
modelDuck.performFly();
modelDuck.performQuack();
针对接口编程
针对接口编程的真实意思是针对“超类型编程”,针对超类型编程这句话可以更明确的说成“变量的声明类型应该是超类型”,通常是一个抽象类或者是一个接口。比如Duck类中的FlyBehavior和QuackBehavior类型的变量。