策略模式是一种很常用的模式,尽管他有一些缺点,但是在我们日常代码中依旧经常用到,另外大家可以看Spring的AopProxy就有用到,今天比较晚了,下次抽时间给大家带来那段源码解析。
首先来看策略模式的定义:定义一组算法,将每个算法都封装 起来,并且使它们之间可以互换。这里依旧举例来说明:假定现有需求,对于用户的各种不同行为增加不同的积分,比如用户登录一次增加5积分,用户注册增加15积分,这就是一个很典型的策略模式的场景。接下来来看类图:
由图中可以看到策略模式的角色分为:
- 抽象策略角色(MemberPointProcessor),该角色为一个接口类,抽象出计算方法,所有具体策略角色都实现此接口。
- 具体实现策略角色(MemberRegistPointProcessor等),该角色为对于抽象策略角色的具体实现。
- 上下文(MemberPointContext)这个角色主要对外做一层封装,可不要,想比如前面说的AopProxy那块代码里其实就是没有这个角色的。
下面来看具体代码实现:
首先抽象策略角色MemberPointProcessor:
public interface MemberPointProcessor {
/**
* 给用户增加积分
*/
void addProcessor();
}
下面为具体策略实现:
public class MemberCertificationPointProcessor implements MemberPointProcessor {
public void addProcessor() {
System.out.println("用户正在执行实名认证操作,给用户增加20积分");
}
}
public class MemberLoginPointProcessor implements MemberPointProcessor {
public void addProcessor() {
System.out.println("用户正在执行登录操作,给用户增加5积分");
}
}
public class MemberRegistPointProcessor implements MemberPointProcessor {
public void addProcessor() {
System.out.println("用户正在执行注册操作,给用户增加15积分");
}
}
接下来是上下文角色:
public class MemberPointContext {
/** 策略类 */
private MemberPointProcessor memberPointProcessor;
public MemberPointContext(MemberPointProcessor memberPointProcessor) {
this.memberPointProcessor = memberPointProcessor;
}
/**
* 执行策略方法
*/
public void process() {
this.memberPointProcessor.addProcessor();
}
}
最后是场景类:
public class MemberOperationService {
/**
* 给用户增加积分
*/
public void addPoint(MemberBehaviorEnum memberBehavior) {
switch (memberBehavior) {
case REGIST:
new MemberPointContext(new MemberRegistPointProcessor()).process();
break;
case LOGIN:
new MemberPointContext(new MemberLoginPointProcessor()).process();
break;
case CERTIFICATION:
new MemberPointContext(new MemberCertificationPointProcessor()).process();
break;
default:
break;
}
}
}
//场景类中用到的枚举
public enum MemberBehaviorEnum {
REGIST("注册"),
LOGIN("登录"),
CERTIFICATION("实名认证");
private String message;
MemberBehaviorEnum(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
接下来调用方法测试:
public static void main(String[] args) {
MemberOperationService service = new MemberOperationServiceImpl();
service.addPoint(MemberBehaviorEnum.REGIST);
service.addPoint(MemberBehaviorEnum.LOGIN);
service.addPoint(MemberBehaviorEnum.CERTIFICATION);
}
执行结果:
用户正在执行注册操作,给用户增加15积分
用户正在执行登录操作,给用户增加5积分
用户正在执行实名认证操作,给用户增加20积分
总结:
优点:
- 由调用者选择具体策略,可自由切换(也是缺点,下面说道),比如某天登录要涨20分了,可以直接让登录的地方选择增加20分的那个算法。
- 避免过多的if()…else if()…。平常我们代码中如果条件判断超过3的把,就可以考虑策略模式,使代码可读性更高。
- 扩展性好,比如要新增用户签到,只需增加一种策略,并且在场景类中加一个case即可,不会对原有其他逻辑造成改动。
缺点:
- 类数量增多,每种策略都是一个类,导致类数量很多,而且比如有的算法,过段时间过时了,又会造成算法新增
- 违背迪米尔法则,即上面所说的优点第一点,场景类需要很清楚的了解每个策略是干嘛的来觉得调用谁,对于场景类的知识依赖度过高
改进办法:参考AopProxy那块的实现,将策略模式和工厂模式结合使用,可解决缺点的第二条。
今天先到这里,下次给大家带来AopProxy那块源码解读。
欢迎关注个人博客:blog.scarlettbai.com