策略模式:
定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
类图

抽象策略角色strategy: 策略类,通常由一个接口或者抽象类实现。
具体策略角色ConcreteStrategyA,ConcreteStrategyB,ConcreteStrategyC:包装了相关的算法和行为。
环境角色Context:持有一个策略类的引用,最终给客户端调用。
优点
- 策略模式提供了管理算法族的办法
- 策略模式提供了可以替换继承关系的方法
- 使用策略模式可以避免使用多重条件转移语句
缺点
- 客户端必须知道所有的策略,并自行决定使用哪一个策略类
- 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。
例子
我们有一套关于鸭子的程序,Duck是超类,实现了鸭子共有的行为如 quack(“呱呱叫”) swim(“游泳”),子类为具体的鸭子分别实现了display()//外表;
RedHeadDuck:红头鸭
MallardDuck:绿头鸭
然后我们需要给鸭子增加飞行的动作,我们在超类中增加了fly()方法
新需求来了,我们需要增加两个子类,分别是
RubberDuck:橡皮鸭 需要重写 quack(),display(),fly()这三个方法
DecoyDuck:诱饵鸭 也需要重写 quack(),display(),fly()这三个方法
如果再继续使用继承,会发现一些问题
- 代码在多个子类中重复实现
- 运行时的行为不容易改变
- 很难知道所有鸭子的全部行为
- 鸭子不能同时又飞又叫
- 改变会牵一发而动全身,造成其他鸭子不想要的改变
为了避免这些问题,我们把共有的行为抽象成接口,通过子类实现接口的方式来增加行为。
显然不是个好方法
设计原则:找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起
设计原则:针对接口编程,而不是针对实现编程
设计原则:多用组合,少用继承
我们使用策略模式来设计
首先我们要分开“变化和不变化的部分”,我们知道Duck中的fly()和quack()会随着鸭子的不同而变化,我们将它们从Duck中取出来,建立一组新类来代表每个行为
这样的设计,可以让飞行和呱呱叫的动作被其他对象复用,因为这些行为已经与鸭子类无关了。
而且我们可以新增一些行为,不会影响到既有的行为类,也不会影响使用到飞行行为的鸭子类
下面整合鸭子的行为。在Duck中增加两个变量,分别为flyBechavior和quackBechavior。在Duck中实现fly和quack1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public abstract class Duck {
QuackBechavior quackBechavior;
FlyBechavior flyBechavior;
public abstract void display();
public void performquack(){
quackBechavior.quack();
};
public void performfly(){
flyBechavior.fly();
};
void swim(){
System.out.println("swim");
};
}
具体鸭子类MallardDuck1
2
3
4
5
6
7
8
9
10
11public class MallardDuck extends Duck {
public MallardDuck(){
quackBechavior = new Quack();
flyBechavior = new FlyWithWings();
}
void display() {
System.out.println("MallardDuck");
}
}
