一、定义:
策略模式(别名:政策):定义一系列算法,把它们一个个封装起来,并且使他们可相互替换。本模式使得算法可独立于使用它的客户而变化。(引自GOF所著《Design Patterns》)
二、角色描述与UML图:
2.1 策略模式的结构中包括三种角色。
(1)策略(Strategy): 策略是一个接口,该接口定义若干个算法标识,即定义了若干个抽象方法,在此场景即是对于各种交通出行方式的一个接口。
(2)具体策略(ConcreteStrategy):具体策略是实现策略接口的类。具体策略实现策略接口所定义的抽象方法,即给出算法标识的具体算法。在此场景中对应着具体的交通出行方式。
(3)上下文(Context):上下文是依赖于策略接口的类,即上下文包含有策略声明的变量。上下文中提供一个方法,该方法依托策略变量调用具体策略所实现的接口中的方法。在此场景中对应的是选择以何种方式回家开启假期。
2.2 UML图
三、优缺点分析:
3.1 优点:
(1) 提供了管理相关的算法策略类,恰当使用继承可以把公共的代码转移到父类里面,避免重复的代码,使得架构也更加灵活。
(2) 提供了可以替换继承关系的办法(组合)。继承也可以处理多种算法或行为,但算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。这样一来算法或行为的使用者就和算法或行为本身混在一起。使得动态改变算法变得复杂甚至不可行,也不符合开闭原则。(3)相对于继承代码更好地得到复用,同时可以避免使用多重条件转移语句。
3.2 缺点:
(1)客户代码需要了解个策略实现的细节,只适用于客户端知道所有的算法或行为的情况。
(2) 策略模式造成很多的策略类,每个具体策略类都会产生一个新类,增加了对象的数目。
四、适用场景:
1)针对同一种问题的多种处理方式、仅仅是因为具体行为有差别时,
2)需要安全的封装多种同一类型的操作时
3)出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。
五、一个简单的例子:
4.1 场景描述:
暑假将至,大家回家的交通出行方式有很多种,对于交通方式的选择也受诸多因素的影响,其中回家距离的远近、经济承受能力、以及对于路途舒适度的选择还有一些外在的不确定因素在不同人之间均存在着差异。因为交通出行的方式在不同个体间存在这一定的差异,若在设计时只提供适用于外地学生的火车、飞机交通出行方式,当有些本地同学在规划回家行程时,对于本地同学来说将是很不适合的一种出行方式;当新的交通方式增加时,回家的方式也会相应的发生变化。因此,大家交通出行方式因人而异,需要适时的变化交通出行的种类。当有新的交通出行方式或变换交通出行方式时,只需要给出一个新的实现Strategy接口的类即可,就能满足回家交通出行方式的规划。而策略模式是处理算法不同变体的一种成熟模式,策略模式通过接口或抽象封装算法的标识,即在接口中定义一个抽象方法,实现该接口的类将实现接口中的抽象方法。策略模式把针对一个算法标识的一系列具体算法分别封装在不同的类中,使得各个类给出具体算法可以互换,因此针对这种场景使用策略模式可以很好解决。
。
4.2 在该具体场景下的策略模式的UML图如下:
4.3 程序代码:
(1)策略(Strategy):
Strategy.java:
public interface Strategy {
public void transport();
}
(2)具体策略(ConcreteStrategy):
ByBus.java:
public class ByBus implements Strategy {
public void transport() {
System.out.println("选择乘坐汽车回家");
}
}
ByTrain.java:
public class ByTrain implements Strategy {
public void transport() {
System.out.println("选择乘坐火车回家");
}
}
ByPlane.java:
public class ByPlane implements Strategy {
public void transport() {
System.out.println("选择乘坐飞机回家");
}
}
(3)上下文(Context):
Context.java:
public class BackHome {
private Strategy strategy;
public BackHome(Strategy strategy){
this.strategy = strategy;
}
public void setStrategy(Strategy strategy){
this.strategy = strategy;
}
public void transport(){
this.strategy.transport();
}
}
(4)模式的使用(Application):
public class Application {
public static void main(String[] args) {
BackHome backhome;
System.out.println("小明没有及时抢到火车票,高铁和飞机票价相对昂贵,所以计划:");
backhome = new BackHome(new ByBus());
backhome.transport();
System.out.println("\n");
System.out.println("小红喜欢火车沿途的风景,所以计划:");
backhome = new BackHome(new ByTrain());
backhome.transport();
System.out.println("\n");
System.out.println("小王家庭经济富裕,选择舒适的回家方式,所以计划:");
backhome = new BackHome(new ByPlane());
backhome.transport();
System.out.println("\n");
}
}
五、程序运行结果: