什么是策略模式?
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
那什么是算法族呢,现在听起来有点抽象,在后面的案例会将它实例化便于理解。案例(参考Head First 设计模式):
需求1.0:模拟鸭子,会游泳和呱呱叫。
public abstract class Duck {
public void quck() {
System.out.println("quck");
}
public void swim() {
System.out.println("swim");
}
//每个鸭子的外观不同,所以是抽象方法
public abstract void display();
}
实例一个鸭子:只是需要继承Duck即可,该类鸭子就可以游泳和呱呱叫。
public class MallardDuck extends Duck{
@Override
public void display() {
System.out.println("绿头鸭");
}
}
需求2.0:给鸭子添加飞行的行为。
idea 1.0:在Duck中添加fly的方法。
public void fly() {
System.out.println("fly");
}
但是这样一来所有继承DucK的鸭子们都具有了fly的行为,包括那个不能飞的鸭子,比如小黄鸭,木头鸭等等。所以idea 1.0 Pass!
idea 2.0:将Duck中的fly方法覆盖,重写。
public class RubberDuck extends Duck {
@Override
public void fly() {
//覆盖,什么都不做
}
@Override
public void display() {
System.out.println("我是橡皮鸭");
}
}
idea 2.0看起来是解决了小黄鸭,木头鸭等鸭子不应该具有飞的行为的问题。但每次加入一次类似种类的鸭子都需要覆盖fly方法,而且如果今后想要再加入新的一种行为,那每一个子类都需要关注这个新进入的方法,是否要覆盖它。这样就会很麻烦。不仅fly方法,其实quck也会有类似问题,每个种类鸭子的叫声也是不一样的。所以idea 2.0也不适用。
idea 3.0:将fly和quack两个方法提取出来,成为两个接口InterfaceFly和InterfaceQuack。只有会飞的鸭子才继承fly的接口,去实现方法。根据idea 3.0示例一只鸭子将变成:
public class RedDuck extends Duck implements InterfaceFly,InterfaceQuack {
@Override
public void display() {
System.out.println("我是红头鸭");
}
@Override
public void fly() {
System.out.println("fly");
}
@Override
public void quack() {
System.out.println("quack");
}
}
idea 3.0问题显而易见,代码无法复用。跟idea 2.0的问题类似。
idea 4.0:将会变化的部分取出并封装起来,不要影响没有变化的部分。这句话的意思是:把鸭子的行为从Duck中取出来。创建两组类FlyBehavior和QuackBehavior,并且实现各自的方法。
fly类
public interface FlyBehavior {
public void fly();
}
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 !!");
}
}
Quack类
public interface QuackBehavior {
public void quack();
}
public class MuteQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("<>");
}
}
public class Squeak implements QuackBehavior {
@Override
public void quack() {
System.out.println("Squeak");
}
}
如果仅仅是这样又和idea 3.0有什么区别么,只是多了具体实现,如果Duck类不变,子类还不是要一个个去继承两个行为实现类。那么现在就来整合鸭子的行为。将鸭子的飞行和呱呱叫的行为委托给别人来处理,就是那两个实现类去处理的。整合后的鸭子是:
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 duck float, even decoys");
}
//添加动态设置,可以动态改变飞的行为
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
现在再次实例一个鸭子
public class MallardDuck extends Duck{
public MallardDuck(){
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("I'm a real Mallard Duck");
}
}
测试
public static void main(String[] args) {
Duck mallard = new MallardDuck();
mallard.display();
mallard.performFly();
mallard.performQuack();
System.out.println("改变鸭子的叫声");
mallard.setQuackBehavior(new MuteQuack());
mallard.performQuack();
mallard.swim();
}
/**
* I'm a real Mallard Duck
* I'm flying !!
* Quack
* 改变鸭子的叫声
* <>
* All duck float, even decoys
*/
- 白话总结
根据案例,其实飞和叫的行为是可变的,而鸭子本身是不可变的,所以就要将两者分开,做到,一方改变不会影响另一方。这里面飞和叫的行为就是一开始所说的算法族。鸭子的行为被封装进入一组类中,可以被轻易地扩充与改变。如果需要在运行时也可以改变行为。
持续跟新中。。。。。。。