策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。
简单的说就是通过一个上下文context 对象,来调用策略接口的具体实现。
定义:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决: if...else 所带来的复杂和难以维护、多方案的切换。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。3、spring底层的Resource接口采用策略模式,ClassPathXmlApplicationContext能根据不同的Resource加载。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。4、符合开闭原则。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
1、通过接口抽象策略,不同的策略算法对接口进行不同的实现。
1、存放key和策略实现类的映射(可以存放在map中、数据库中、枚举中)。
2、初始化具体策略class(可以使用工厂模式,也可以通过spring来管理bean)。
工厂模式初始化具体策略class时要注意多线程的问题。如果要在spring中集成就可以不用到工厂来初始化class。
以集成spring,枚举来管理映射为例(当然如果硬要用beanId来作为客户端传入,也可以省略掉枚举)。
public interface MyStrategy {
/**
* 做某些事情
* @return
*/
String doSomething();
}
接口实现:
@Component
public class HelloStrategy implements MyStrategy {
@Override
public String doSomething() {
return "Hello world";
}
}
Context上下文管理
@Component
public class ContextStrategy {
/**
* 获取具体策略实现
* @return
*/
public String getStrategy(String code) {
if (StringUtils.isEmpty(code)) {
return "code不能为空!.....";
}
//枚举里映射了code和spring bean的Id
String strategyBeanId = MyEnum.getId(code);//通过code拿到beanId
MyStrategy payStrategy = SpringUtils.getBean(strategyBeanId, MyStrategy.class);//通过beanId拿到bean对象
return payStrategy.doSomething();
}
}
枚举映射
public enum MyEnum {
/**
* Hello
*/
HELLO("hello","helloStrategy");
MyEnum(String key, String id) {
this.setKey(key);
this.setId(id);
}
public static String getId(String key){
for(MyEnum pay: MyEnum.values()){
if(StringUtils.equals(pay.getKey(),key)){
return pay.getId();
}
}
return "not find";
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
/**
* key
*/
private String key;
/**
* bean的id名字
*/
private String id;
}
全部评论