阅读 254

设计模式 | 策略模式

这是我参与8月更文挑战的第 31 天,活动详情查看:8月更文挑战

8月更文的活动一下就到最后一天了,而我也高产了一整个月,实在是太难了

图片.png

何为策略模式

该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

从描述上来看,和多态的概念又比较类似(子类对父类的多种表现形态)

在外部的方法调用中,我们需要选择传递某个的策略,来完成一件事

优点

定义好的策略是可复用的,也能够根据需要进行切换,避免了被硬编码到代码中

缺点

随着策略的数量不断膨胀,调用方就会陷入到不知道选择应用哪一个策略困境

代码示例

UML 图

图片.png

环境类

包含一个策略实例,通过接口引用的方式。同时,需要执行策略中的方法来做一件事情

class Context {
  Strategy strategy;
  // getter/setter
  public void contextMethod(){
    // ...
    strategy.method();
    // ...
  }
}
复制代码

策略模块

一般在使用策略模式的时候,我们手里都会存在几个可选的策略项,也可以说是内置几个初始策略

那么,这个策略模块,设计就是 策略接口+几个内置的策略实现类

@FunctionInterface
interface Strategy {
  void method();
  Strategy s1 = () -> {
  };
  Strategy s2 = () -> {
  };
  Strategy s3 = () -> {
  };
}
复制代码

如果我们需要扩展新的策略,那么,直接继承自 Strategy 并实现其中的方法即可

客户端调用

初始化环境,赋予一个策略,然后调用方法

Context ctx = new Context();
ctx.setStrategy(Strategy.s1);
ctx.contextMethod();
复制代码

使用场景

一般情况下,当我们需要通过if...else if 的方式来选择执行某一个动作,或者说是,我们期望代码中的某一块是能够切换的,并且,切换后还不影响到其他位置

像我的这一篇文章 设计可复用的消息推送模块,就有策略模式的影子

Group 中有一个Condition 的实例,这个实例,会根据用户的定义来切换,切换并不影响他的核心目的 —— 判断条件是否满足要求,至于需要怎么判断,就看用户选择哪一个测落,Condition 的代码如下

@FunctionalInterface
public interface Condition {
	// 判断条件是否满足
	boolean judge(ErrorMsg msg);
	
	// 超过一定的异常等级则判定为 true
	final Condition ERROR_LEVEL = (ErrorMsg msg) -> {
		return Integer.valueOf(msg.level) > 3 ? true : false;
	};
	// 判断时间在白班区间 [8:00, 20:00)
	final Condition DAY_WORK = (ErrorMsg msg) -> {
		int hour = LocalDateTime.now().getHour();
		return (hour >= 8 && hour < 20) ? true : false;
	};
	// 夜班时间判断
	final Condition NIGHT_WORK = (ErrorMsg msg) -> {
		return !DAY_WORK.judge(msg);
	};
	
}
复制代码

将所有的判断模式封装到了 Condition 中,客户端根据需要直接调用即可,或者不够用的话,额外去实现也没问题

文章分类
后端
文章标签