也称作政策模式(Policy Pattern)
Define a family of algrithuns, encapusulate each one ,and make them interchagenable
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换
类图
Context封装角色:
也叫作上下文,起承上启下封装做用,屏蔽高层模块对策略算法的直接访问,封装可能存在的变化。与Strategy是聚合关系
Strategy抽象策略角色:
策略、算法家族的抽象,通常为接口,定义每个策略或者算法必须具有的方法和属性。
ConcreteStrategy具体决策实现类:
实际抽象策略中的操作,该类具有具体的算法
代码实现
public interface Strategy {
//策略模式的运算法则
public void doSth();
}
public class ConcreteStrategyA implements Strategy {
@Override
public void doSth() {
System.out.println("策略1,....人之初,性本善");
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void doSth() {
System.out.println("策略2,....36计,走为上策");
}
}
/**
* 封装类
* @author isc
*
*/
public class Context {
//抽象策略
private Strategy strategy=null;
//构造函数中设置策略
public Context(Strategy strategy){
this.strategy=strategy;
}
//封装后的策略方法
public void doAntThing(){
this.strategy.doSth();
}
}
测试类:
public class Client {
public static void main(String[] args) {
// 声明一个具体的策略
Strategy strategy1 = new ConcreteStrategyA();
Strategy strategy2 = new ConcreteStrategyB();
//声明上下文对象
Context ctx1 = new Context(strategy1);
ctx1.doAntThing();
Context ctx2 = new Context(strategy2);
ctx2.doAntThing();
}
}
输出:
策略1,....人之初,性本善
策略2,....36计,走为上策
优缺点:
优点:
算法可以自由切换,只要实现具体抽象类,就可以成为策略家族的一个成员,通过封装角色对其进行封装,可以实现自由切换;
扩展性良好:在现有系统中增加一个策略它容易了,只需要实现接口就行了。
缺点:
策略类数量多,复用可能小;
所有策略都需要对外暴露才能决定使用哪个策略。
策略家族中的具体策略数超过4个则需要考虑使用混合模式,决绝策略类膨胀和对外暴露的问题,否则日后维护不便。
使用场景
多个类只有在算法或者行为上稍有不同的场景:算法需要自由切换,需要屏蔽算法规则的场景。
例子1:一个菜单功能能够根据用户的“皮肤”首选项来决定是否采用水平的还是垂直的排列形式。同事可以灵活增加菜单那的显示样式。
例子2:出行旅游:我们可以有几个策略可以考虑:可以骑自行车,汽车,做火车,飞机。每个策略都可以得到相同的结果,但是它们使用了不同的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度 。
策略模式与代理模式区别
<代理模式类图>
可以看出,策略模式封装角色和被封装策略不是同一个接口,而代理模式的封装角色和被代理角色都实现统一个接口。
策略枚举
/**
* 抽象类的元素默认去实现一遍构造函数即相当于创建此类的一个实例,需要先实现其中定义的抽象方法
* @author isc
*/
public enum ConcretStrategy {
StrategyA(){
@Override
public void doSth() {
System.out.println("策略1....");
}
},
StrategyB(){
@Override
public void doSth() {
System.out.println("策略2....");
}
};
//声明一个抽象函数
public abstract void doSth();
}
public class Client {
public static void main(String[] args) {
ConcretStrategy.StrategyA.doSth();
ConcretStrategy.StrategyB.doSth();
}
}
把原有定义在抽象策略中的方法移植到枚举中,每个枚举成员就变成了一个具体的策略,枚举策略是一个比较优秀和方便的模式,但是它收到枚举类型的限制,每个枚举项都是public\static\final的,扩展性收到一定的约束,因此在系统开发中,比较适合担当不经常发生变化的角色。