设计模式 - state 状态模式 与 strategy 策略模式 分析实现
程序员文章站
2022-06-17 17:09:56
...
策略模式-意图:允许用户根据需要来处理算法方案的变化
状态模式-意图:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
两种模式都由三个角色组成:
(1)环境(Context)角色:持有一个Strategy/state的引用(或以提供的形式,针对策略模式个人认为当具体的行为是个无状态实体时,没必要以持有的方式来实现,这样会造成改变策略时每次都需要创建一个新的环境和新的策略实体,但其实只要环境中有个提供具体行为的静态方法,每个具体行为都是一个单例就可以了)
(2)抽象策略/状态(Strategy/state)角色:这是一个抽象角色,通常由一个接口或者抽象类实现。此角色给出所有的具体策略/状态类的接口。
(3)具体策略/状态(ConcreteStrategy/ConcreteState)类,包装了相关的算法或者状态行为。
这两种模式都能有效的解决过度冗长的case,if else等逻辑判断问题。
比如:
if(条件1){
...
}else if(条件2){
...
}else if ...
如果只是三个判断左右,看起来并无大碍,当存在十几个判断体,且每个判断体内逻辑及其复杂时,这将看起来非常冗长,对于开发和维护无疑是个巨大的痛点。下面将针对两种设计模式做简单实现:
1、策略模式
样例:在一个系统中存在上百个条款,其中有十几个条款需要针对不同的场景定制不同的条款内容,这个例子不存在状态的转换(比如在策略A执行过程中因某种因素转到策略B执行):
1.1 条款简体
/**
* 条款简体
* <br>实例化方式:ClauseTools.newClause(code,name,value);
* @author zhanghaowen
*/
public class Clause{
private String code;
private String name;
private String value;
public Clause(String code,String name,String value){
this.code =code;
this.name =name;
this.value = value;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "Clause [code=" + code + ", name=" + name + ", value=" + value + "]";
}
}
1.2 编写策略接口、行为实体
/**
* 策略接口
* @author zhanghaowen
*
*/
public interface ClauseStrategy {
//公共处理接口
//这里的ParamsHolder 是一个用来判断的参数集
Clause handle(Clause clause,ParamsHolder params) throws Exception ;
}
/**
* 策略抽象类
* @author zhanghaowen
*
*/
public abstract class AbstractClauseStrategy implements ClauseStrategy{
/**
* 特殊条款内容模板
*/
public static final String TEMPLATE_T0205_UP50 = "******非公开内容*******";
}
/**
* 默认条款策略实体
* @author zhanghaowen
*
*/
public class ClauseStrategyDefault extends AbstractClauseStrategy{
@Override
public Clause handle(Clause clause,ParamsHolder params) {
return clause;
}
}
1.3 编写策略环境
这里使用缓存形式,因为每个策略实体都是无状态类,是线程安全的,可以共用。
public class ClauseContext {
/**类路径前缀*/
public static final String BASE_PREFIX = "com.xxx.tools.clause.strategy.impl.extend.ClauseStrategy";
/**策略行为实体缓存*/
public static Map<Integer, ClauseStrategy> strategys = new HashMap<Integer, ClauseStrategy>();
/**
* 获取具体策略行为
* 这里不采用持有的方式,而是开放一个提供具体策略行为的静态方法。
* 这些具体策略行为都已缓存的形式存在
* @param clauseCode
* @return ClauseStrategy
* @throws Exception
*/
public static ClauseStrategy getStrategy(String clauseCode) throws Exception{
ClauseStrategy clauseStrategy = null;
Class<?> clazz = null;
if(StringUtils.isNotBlank(clauseCode)) {
String classKey = BASE_PREFIX+clauseCode;
try {
clazz = Class.forName(classKey);
} catch (ClassNotFoundException e) {
//这里不阻断,找不到类则使用默认策略
clazz = ClauseStrategyDefault.class;
}
}
//读缓存
clauseStrategy = strategys.get(clazz.hashCode());
//缓存为空时,载入新的实例到缓存
if(clauseStrategy==null) {
clauseStrategy = (ClauseStrategy) clazz.newInstance();
strategys.put(clazz.hashCode(), clauseStrategy);
}
return clauseStrategy;
}
}
1.4 使用策略
Clause clause = ClauseContext.getStrategy(clause.getCode()).handle(clause, params)
2 状态模式
2.1 状态接口、具体行为
public interface State {
//行为动作
void doAction();
//设置时间
void setClock(Context context,int hour);
}
public class ConcreteStateA implements State {
private static ConcreteStateA singleton = new ConcreteStateA();
public static ConcreteStateA getSingleton() {
return singleton;
}
@Override
public void doAction() {
System.out.println("ConcreteStateA action:白天");
}
@Override
public void setClock(Context context, int hour) {
if(hour<9||hour>17) {
context.setState(ConcreteStateB.getSingleton());
}
}
}
public class ConcreteStateB implements State {
private static ConcreteStateB singleton = new ConcreteStateB();
public static ConcreteStateB getSingleton() {
return singleton;
}
@Override
public void doAction() {
System.out.println("ConcreteStateB action:黑夜");
}
@Override
public void setClock(Context context, int hour) {
if(hour>=9&&hour<=17) {
context.setState(ConcreteStateA.getSingleton());
}
}
}
2.1 状态环境
public class Context {
State state;
public Context() {
}
public Context(State state) {
this.state = state;
}
public void setClock(int hour) {
this.state.setClock(this, hour);
}
public void doAction() {
this.state.doAction();
}
public State getState() {
return state;
}
public State setState(State state) {
this.state = state;
return this.state;
}
public void printClass() {
System.out.println(this.state.getClass().toString());
}
}
2.2 测试
public class Test {
public static void main(String[] args) throws Exception, IllegalAccessException {
Context context = new Context();
//设置当前状态
context.setState(ConcreteStateA.getSingleton());
context.setClock(7);
context.doAction();
context.setClock(8);
context.doAction();
context.setClock(9);//九点,此时状态变白天了
context.doAction();
}
}
输出:
ConcreteStateB action:黑夜
ConcreteStateB action:黑夜
ConcreteStateA action:白天