策略模式的作用在于方便代码维护以及扩展性。
策略模式主要包含三个元素:上下文对象、策略接口、策略实现类。
举一个常见的例子:支付功能,支付的方式存在微信、支付宝、银行卡等等。假设项目开始客户只需要微信支付,那么你只需要正常写微信支付的逻辑即可,后面客户又想要加一个支付宝支付,这时候加个if条件判断,然后加上支付宝的支付逻辑就行,再后面又想加银行卡支付、抖音支付一堆支付,如果一直加if判断也是可以解决的,如果觉得所以支付的逻辑都在if代码块中,导致代码又臭又长,那么可以将各个支付的逻辑提取成方法,这样代码就看起来美观了一些,后面加一种方式就加一个支付方法,同时修改支付功能的主方法中加一个if分支。
使用策略模式,那么就可以避免修改支付功能的主方法,只需要加一个策略接口实现类(相当于新增一个支付方法)。从以上例子来看,策略模式相较于if代码块多一个不需要修改支付功能的主方法的优点(可读性和维护性我认为是看个人习惯)。
再举一个例子:你们的项目需要打包(sdk、jar、war等等)提供给外部(其它系统、其它部门或其它公司等等),还是支付功能,你们只实现了微信支付和支付宝支付,但是外部调用者需要银行卡支付,这时候难道要你们来增加这个支付方法,再打包给他吗?那如果又要加别的支付方法呢?多一个支付方法你们就改一次代码吗?
这个时候,使用策略模式就能解决这个问题,给外部开放策略接口,调用者只需要实现策略类,就可以新增支付方法,调用者想加什么就加什么,不需要你们来操心。这个就是策略模式另一个优点:扩展性,也符合开放 - 封闭原则。
1、策略接口
定义了一个公共接口,所有策略类都必须实现这个接口。
/**
* 同步指导书文件策略接口
*/
public interface SyncFileStrategy {
/**
* 指导书文件关联业务类型
*/
String getType();
/**
* 同步文件
*/
void sync(SyncFileBo bo);
}
2、策略实现类
实现了策略接口的具体类,每个类都定义了一种具体的策略。
/**
* 文件策略
*/
@Service
@RequiredArgsConstructor
public class FileSyncFileStrategy implements SyncFileStrategy {
@Override
public String getType() {
return SyncFileType.FILE;
}
@Override
public void sync(SyncFileBo bo) {
//具体实现
}
}
/**
* 任务策略
*/
@RequiredArgsConstructor
@Service
public class TaskSyncFileStrategy implements SyncFileStrategy {
@Override
public String getType() {
return SyncFileType.TASK;
}
@Override
public void sync(SyncFileBo bo) {
//具体实现
}
}
/**
* 用户组策略
*/
@Service
@RequiredArgsConstructor
public class UserGroupSyncFileStrategy implements SyncFileStrategy {
@Override
public String getType() {
return SyncFileType.USER_GROUP;
}
@Override
public void sync(SyncFileBo bo) {
//具体实现
}
}
......
3、上下文对象
负责调用具体的策略,并根据客户端的请求选择合适的策略来执行。
/**
* 同步指导书文件上下文对象
*/
@RequiredArgsConstructor
@Service
public class SyncFileFactory {
private final Map<String, SyncFileStrategy> map = new ConcurrentHashMap<>();
private final ApplicationContext applicationContext;
@PostConstruct
private void init() {
Map<String, SyncFileStrategy> beansOfType = applicationContext.getBeansOfType(SyncFileStrategy.class);
beansOfType.forEach((k, v) -> map.put(v.getType(), v));
}
/**
* 同步文件
*/
public void sync(SyncFileBo bo) {
getStrategy(bo.getSyncFileType()).sync(bo);
}
public SyncFileStrategy getStrategy(String syncFileType){
SyncFileStrategy syncFileStrategy = map.get(syncFileType);
if (syncFileStrategy != null){
return syncFileStrategy;
}else {
throw new ServiceException("错误的策略类型!");
}
}
}
4、使用示例
1、注入上下文对象
@Autowired
private SyncFileFactory syncFileFactory;
2、在方法中使用
SyncFileBo syncFileBo = new SyncFileBo();
syncFileBo.setSyncFileType(SyncFileType.USER_GROUP);
syncFileFactory.sync(syncFileBo);