1、策略模式
if…else…的判断语句是大家常用的处理逻辑分支的方法,但是如果逻辑分支比较多,不仅可读性差,维护也困难,策略模式就可以优雅的解决if…else…过多带来的问题。
举例说明,比如有三种类型的物资A,B,C;调度不同的物资用不同的业务要处理,常规方式就会通过if…else…判断物资类型来处理,下面演示策略模式如何处理。
首先,定义一个接口,提供两个方法:(1)获取当前资源的类型;(2)处理当前逻辑分支业务代码。
public interface DispatchResourceStrategy {
//属于哪种资源类型
ResourceTypeEnum getType();
//封装的业务代码
void dispatchResource(Object objectparam);
}
然后,有多少if…else…分支就新建多少接口的实现类,在实现类里实现分支的业务逻辑。
@Component
public class ADispatchResolve implements DispatchResourceStrategy {
@Override
public ResourceTypeEnum getType() {
return ResourceTypeEnum .A_RESOURCE;
}
@Override
public void resolve(Object objectparam) {
//A类型物资调度具体逻辑
}
}
B,C类型物资调度实现类省略,步骤与A物资一致
最后,将所有分支的实现添加到map集合里,这样就能根据类型取出需要的实现类,调用对应的方法。
@Component
public class TestService implements ApplicationContextAware{
private Map<ResourceTypeEnum , DispatchResourceStrategy > strategyMap = new ConcurrentHashMap<>();
// 使用策略模式
public void dispatch(ResourceTypeEnum resourceEnum, Object objectParam) {
DispatchResourceStrategy dispatchStrategy = strategyMap .get(resourceEnum);
if (dispatchStrategy != null) {
dispatchStrategy .resolve(objectParam);
}
}
//把不同策略放到map
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, DispatchResourceStrategy > beansMap = applicationContext.getBeansOfType(DispatchResourceStrategy .class);
beansMap.values().forEach(strategyImpl -> strategyMap .put(strategyImpl.getType(), strategyImpl));
}
}
2、责任链模式
责任链模式的定义是:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到所有链上的对象处理完为止。在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,请求会自动进行传递。所以责任链将请求的发送者和请求的处理者解耦了。
举例说明:
1、先定义一个接口或者抽象类,提供:1、链上的对象;2、设置链上对象的get,set方法;3、链上对象实现用于处理业务的方法。
public interface ChainHandler {
//责任链中的下一个对象
private ChainHandler nextHandler;
/**
* 责任链的下一个对象
*/
public void setNextHandler(ChainHandler nextHandler){
this.nextHandler = nextHandler;
}
/**
* 具体参数拦截逻辑,给子类去实现
*/
public void filter(Object param) {
doFilter(param);
// 递归传递责任链
if (getNextHandler() != null) {
getNextHandler().filter(request, response);
}
}
public ChainHandler getNextHandler() {
return nextHandler;
}
abstract void doFilter(Object param);
}
2、再定义链上的对象,实现接口即可。
@Component
@Order(1) //order注解中的数字代表链上对象执行的顺序,1代表最先执行
public class CheckParamHandler implement ChainHandler {
@Override
public void doFilter(Object param) {
System.out.println("责任链节点1执行......");
}
}
同理,想在责任链上添加几个对象就按照责任链1实现接口,重写方法,设置在责任链中的执行顺序即可。
3、使用责任链模式
@Component("ChainTest")
@Data
public class ChainTest {
//注入所有的责任链对象
@Autowired
private List<ChainHandler> chainHandlerList;
private ChainHandler chainHandler;
// 将责任链对象链接起来
@PostConstruct
public void initializeChainHandler(){
for(int i = 0;i<chainHandlerList.size();i++){
if(i == 0){
chainHandler = chainHandlerList.get(0);
}else{
ChainHandler currentHander = chainHandlerList.get(i - 1);
ChainHandler nextHander = chainHandlerList.get(i);
currentHander.setNextHandler(nextHander);
}
}
}
//直接调用这个方法使用
public void test(Object param) {
// 责任链
chainHandler.filter(param);
}
}
3、模板方法模式
开发中会遇到这种情况,几个不同的对象要执行相同的几个步骤,但是具体的执行逻辑不同;例如我在开发中遇到的一个场景,我这里需要从第三方接口获取数据,二次加工,返回给我们的前端,其中涉及到的步骤有发起请求,数据存入缓存,更新缓存等,如果每个接口都单独定义几个方法去执行,就会造成代码的冗余,不够简洁,所以这里可以使用模板方法模式去优化,蒋一些通用的方法定义在接口或者抽象类中,具体执行逻辑交给每一个子类去重写。
模板方法模式的定义:定义一个操作中的算法的骨架流程,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。它的核心思想就是:定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现,这样不同的子类就可以定义出不同的步骤。
下面举例说明
1、定义一个抽象类,包含通用的流程方法,需要子类重写的方法定义为抽象方法。
public abstract class CacheBuilder<T extends Entity<String, String>> {
public boolean needInit() {
return true;
}
// 是否需要刷新,默认TRUE
public boolean needRefresh() {
return true;
}
// 定义子类执行顺序
public abstract Integer order();
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public abstract String redisKey();
public Function<T, T> value() {
return Function.identity();
}
// 交给子类实现具体的逻辑
public abstract List<T> apiList();
//
public boolean buildCache() {
String redisKey = redisKey();
List<T> list = null;
int retryTime = retryTime(), i = 0;
while (i < retryTime) {
try {
list = apiList();
break;
} catch (Exception e) {
log.error("api请求缓存数据失败 key=[{}]", redisKey, e);
}
i++;
}
if (list == null || list.isEmpty()) {
return false;
}
Map<String, T> map = list.stream().collect(Collectors.toMap(key(), value(), (pre, next) -> {
log.debug("pre=[{}] next=[{}]", pre, next);
return pre;
}));
clearCache(redisKey);
redisTemplate.opsForValue().multiSet(map);
return true;
}
public void initCache() {
buildCache();
}
public void refreshCache() {
buildCache();
}
public void clearCache(String key) {
String pattern = RedisConstants.pattern(key);
Set<String> keys = redisTemplate.keys(pattern);
if (keys != null) {
redisTemplate.delete(keys);
}
}
}
2、子类实现差异化步骤
@Component
@RequiredArgsConstructor
public class MyCacheBuilder extends CacheBuilder<Wbs> {
private volatile boolean initialed = false;
@Override
public boolean needRefresh() {
return false;
}
@Override
public Integer order() {
return 10;
}
@Override
public String redisKey() {
return RedisConstants.WBS_KEY;
}
@Override
public Function<Wbs, String> key() {
return wbs -> RedisConstants.key(redisKey(), wbs.getWbsFullNo());
}
// 子类差异化逻辑实现
@Override
public List apiList() {
List<Project> projectList = baseApiService.projectList();
if (CollectionUtil.isEmpty(projectList)) {
return new ArrayList<>();
}
List<Section> sections = baseApiService.sectionList();
if (CollectionUtil.isEmpty(sections)) {
return new ArrayList<>();
}
......
return res;
}
@Override
public void initCache() {
if (!initialed) {
initialed = buildCache();
}
}
@Override
public void refreshCache() {
initCache();
if (initialed) {
}
}
}
4、单例模式
单例模式,保证一个类仅有一个实例,并提供一个获取这个唯一实例的入口。单例模式有几种写法:懒汉模式,饿汉模式,双重校验锁等实现方式。
懒汉模式:用到的时候再实例化
public class LanHanSingleton {
private static LanHanSingleton instance;
private LanHanSingleton(){
}
public static LanHanSingleton getInstance(){
if (instance == null) {
instance = new LanHanSingleton();
}
return instance;
}
}
这种写法在高并发的场景下有线程安全问题,可以加上synchronize关键字
饿汉模式:不管用没用到先实例化一个出来
public class EHanSingleton {
private static EHanSingleton instance = new EHanSingleton();
private EHanSingleton(){
}
public static EHanSingleton getInstance() {
return instance;
}
}
双重检验锁:
public class DoubleCheckSingleton {
private volatile static DoubleCheckSingleton instance;
private DoubleCheckSingleton() { }
public static DoubleCheckSingleton getInstance(){
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
这是线程安全的单例模式,比懒汉模式安全,比饿汉模式节省内存空间。