策略模式
策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。此模式让算法的变化独立于使用算法的客户
此算法体现了几个设计原则:
- 把变化的代码从不变的代码中分离出来。
- 针对接口编程而不是具体类(定义了策略接口)。
- 多用组合/聚合,少用继承(客户通过组合方式使用策略。
策略模式的关键是:分析项目中变化部分与不变部分 。
概括:
定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
核心: 多用组合/聚合 少用继承;用行为类组合,而不是行为的继承。
策略模式与模板模式的区别:
- 模板模式一般只针对一套算法,注重对同一个算法的不同细节进行抽象提供不同的实现。而策略模式注重多套算法多套实现。
模式结构
- 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
- 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
类图
优缺点
优点:
- 可以在运行时切换对象内的算法
- 开闭原则,客户端增加行为不用修改原有代码,只要添加一种策略(或者行为)即可,避免了使用多重转移语句(if…else if…else)。
- 可以将算法的实现和使用算法的代码隔离开来。
- 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
缺点:
- 如果算法极少发生改变, 那么没有任何理由引入新的类和接口。 使用该模式只会让程序过于复杂。
- 客户端必须知晓策略间的不同——它需要选择合适的策略。
- 每添加一个策略就要增加一个类,当策略过多是会导致类数目庞大。
应用场景
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
- 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
- 当有许多仅在执行某些行为时略有不同的相似类时, 可使用策略模式。
- 如果算法在上下文的逻辑中不是特别重要, 使用该模式能将类的业务逻辑与其算法实现细节隔离开来。
- 当类中使用了复杂条件运算符以在同一算法的不同变体中切换时, 可使用该模式。
示例代码
public class AquaticBehavior implements RunBehavior{
@Override
public void run(String name) {
System.out.println(name+"水中行");
}
}
public class Boat extends VehicleContext{
public Boat(String name){
this.name = name;
}
@Override
public void show() {
manned();
needOil();
run();
}
}
public class Car extends VehicleContext{
public Car(String name){
this.name = name;
}
@Override
public void show() {
manned();
needOil();
run();
}
}
public class Plane extends VehicleContext{
public Plane(String name){
this.name = name;
}
@Override
public void show() {
manned();
needOil();
run();
}
}
public interface RunBehavior {
void run(String name);
}
public class SkyBehavior implements RunBehavior{
@Override
public void run(String name) {
System.out.println(name+"天上飞");
}
}
public class StrategyPattern {
public static void main(String[] args) {
VehicleContext context = new Car("汽车");
context.setBehavior(new WayBehavior());
context.show();
VehicleContext planeContext = new Plane("飞机");
planeContext.setBehavior(new SkyBehavior());
planeContext.show();
VehicleContext boatContext = new Boat("轮船");
boatContext.setBehavior(new AquaticBehavior());
boatContext.show();
}
}
public abstract class VehicleContext {
protected RunBehavior behavior;
protected String name;
public void setBehavior(RunBehavior behavior){
this.behavior = behavior;
}
public void manned(){
System.out.println("交通工具可以载人");
}
public void needOil(){
System.out.println("交通工具运行需要油");
}
public void run(){
if (behavior != null) behavior.run(name);
}
public abstract void show();
}
public class WayBehavior implements RunBehavior{
@Override
public void run(String name) {
System.out.println(name+"路上跑");
}
}