赞
踩
一、概述
我们工作的业务代码从注释、命名、方法和异常等多方面实现整洁代码,但是感觉不够简洁,不够优雅,因为这是设计上的不足,总结就是抽象不够、可读性低、不够健壮。那这些就用到了设计模式。
java本身没有设计模式,但是随着时代的发展,写代码是人多了,他们便总结出了一套能提高开发和维护效率的套路,这就是设计模式。设计模式不是什么教条或者范式,它可以说是一种在特定场景下普适且可复用的解决方案,是一种可以用于提高代码可读性、可扩展性、可维护性的最佳实践。
二、短信发送策略
我目前在职的公司主营业务是智能语音外呼,主要是用机器人语音外呼替代人工,为了提升外呼之后的转换,通常会给客户发送一条挂机短信。但是因为通信通道的不稳定性以及业务复杂性(每个通道能发送的短信模板都是不一样的,比如营销类短信,游戏类短信),导致我们经常要对接各种短信通道。多数的小伙伴就会写出以下的代码:
if(type=="A通道"){
//按照A通道的对接文档进行对接
}else if(type=="B通道"){
//按照B通道的对接文档进行对接
}else{
//按照默认格式解析
}
这个代码可能会存在哪些问题呢?
说得专业一点的话,就是以上代码,违背了面向对象编程的开闭原则、单一原则以及迪米特法则。
如果你的代码就是:有多个if…else等条件分支,并且每个条件分支,可以封装起来替换的,这个案例就可以使用策略模式和适配器模式来优化。
首先是策略模式:策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。
策略模式通常包含以下角色:
然后是适配器模式:适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
适配器模式包含以下主要角色:
// 策略接口 interface Strategy { void send(Object ... params); } //适配者接口 class Adaptee { public void specificRequest() { System.out.println("适配者中的业务代码被调用!"); } } // 联通策略+对象适配器类 class CUCC implements Strategy { private CUCCAdapteeService cuccService; @Override public void send(Object... params) { CUCCRequest request = new CUCCRequest(); // 构建入参 request.setCUCCReq(params); cuccService.specificRequest(request); } } // 移动策略+对象适配器类 class CMCC implements Strategy { private CMCCAdapteeService cmccService; @Override public void send(Object... params) { CMCCRequest request = new CMCCRequest (); // 构建入参 request.setCMCCReq(params); cmccService.specificRequest(request); } } // 电信策略+对象适配器类 class CTCC implements Strategy { private CTCCAdapteeService ctccService; @Override public void send(Object... params) { CTCCRequest request = new CTCCRequest (); // 构建入参 request.setCTCCReq(params); ctccService.specificRequest(request); } }
CUCCAdapteeService 、CMCCAdapteeService 、CTCCAdapteeService 都是对象适配器类
代码经过优化后,虽然结构和设计上比之前要复杂不少,但考虑到健壮性和拓展性,还是非常值得的。
// 使用分支判断获取的策略上下文 class StrategyContext { public static Strategy getStrategy(String sendType) { switch (sendType) { case "CMCC": return new CMCC(); case "CUCC": return new CUCC(); case "CTCC": return new CTCC(); default: throw new IllegalArgumentException("sendType error!"); } } } // 优化后的策略服务 class SendService { public void send(String sendType , Object ... params) { Strategy strategy = StrategyContext.getStrategy(sendType); strategy.send(params); } }
其实这就是工厂模式,定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。工厂模式一般配合策略模式一起使用。
但是这里发现策略类是无状态的模型,那就可以将策略类单例化以减少开销,并实现自注册的功能彻底解决分支判断。
所以在策略环境类StrategyContext 中使用一个注册表来记录各个策略类的注册信息,并提供接口供策略类调用进行注册。同时使用饿汉式单例模式去优化策略类的设计:
// 策略上下文,用于管理策略的注册和获取
class StrategyContext {
private static final Map<String, Strategy> registerMap = new HashMap<>();
// 注册策略
public static void registerStrategy(String sendType, Strategy strategy) {
registerMap.putIfAbsent(sendType, strategy);
}
// 获取策略
public static Strategy getStrategy(String sendType) {
return registerMap.get(sendType);
}
}
// 抽象策略类
abstract class AbstractStrategy {
// 类注册方法
public void register() {
StrategyContext.registerStrategy(getClass().getSimpleName(), this);
}
}
// 饿汉式单例CMCC策略 class CMCC extends AbstractStrategy implements Strategy { private static final CMCC instance = new CMCC(); private CMCCAdapteeService cmccService; private CMCC() { register(); } public static CMCC getInstance() { return instance; } @Override public void send(Object... params) { CMCCRequest request = new CMCCRequest (); // 构建入参 request.setCMCCReq(params); cmccService.specificRequest(request); } } ..........................................
如果使用了Spring框架,还可以利用Spring的Bean机制来代替上述的部分设计,直接使用@Component和@PostConstruct注解即可完成单例的创建和注册,代码会更加简洁。
至此,经过了多次反思和优化,得到了一套低耦合高内聚,同时符合开闭原则的设计。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。