这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
实际业务场景
最近在项目中需要开发消息发送平台,需要根据 type 值判断来进行相应的业务处理以及消息发送方式,这样就涉及到重复的 if-else 的问题,为了解决这样重复的代码来造成的代码冗余的问题,所以考虑使用策略模式,根据具体的场景执行对应的策略,来解决问题。本文简单写一个测试 Demo,实际开发需要根据具体业务,具体实现对应的业务逻辑。
具体实现
当我们遇到这样的逻辑处理时,第一反应是针对 type 进行 if…else… 或者是 switch 的逻辑判断,从而区分不同业务逻辑处理。
基于 if…else… 的伪代码
1 | java复制代码public int sendMessage(int type, Message message) { |
假设上面的代码是用来对消息进行多渠道的发送,根据不同 type 来进行发送方式的选择。当然真实的业务场景不可能是这么简单的判断。
首先对照一下设计模式的开闭原则:面对扩展开放,面对修改关闭。
上述代码,如果某个发送方式改变了,那么这段代码就要进行修改,或者如果新增了一个发送方式,这段代码同样需要修改。一旦修改必然会影响到其他方式的业务逻辑。完全不符合开闭原则,同时代码中还充斥着大量的 if…else…,如果业务复杂,代码会急速膨胀。
那么,下面我们就针对以上实例,用策略模式来进行重新设计。
基于策略模式的伪代码
首先定义一个发送消息的接口 ISendMessageStrategy。实战过程中可根据具体情况采用接口或抽象类。
1 | java复制代码public interface ISendMessageStrategy { |
在接口中提供一个方法,也就是发送消息的方法。这里因为是接口,所以定义的方法就需要子类必须实现。下面便是针对此接口的具体实现,不同的发送方式有不同的实现。
1 | java复制代码/** |
我们来实现一个持有接口 ISendMessageStrategy 的角色类 SendMessageHandler
1 | java复制代码public class SendMessageHandler { |
最后,我们来看一下如何调用该策略类
1 | java复制代码public class Test { |
使用 Spring 来管理对象
上面的改进已经避免了大量的 if… else…,此时如果项目使用的是 Spring 项目,我们再进一步改进, 此时主要利用 Spring 的 @Autowired 注解来将实例化的策略实现类注入到一个 Map 当中,然后通过 key 可以方便的拿到服务。
首先将策略实现类通过@Service 注解进行实例化,并指定实例化的名称。以短信发送的实现为例:
1 | kotlin复制代码@Component("mobileSendMessageStrategy") |
其他策略实现类与上相同,依次实例化。最后改造环境角色类为 SendMessageHandler:
1 | java复制代码@Component |
applicationContext.getBeansOfType(ISendMessageStrategy.class) 会将容器中 ISendMessageStrategy 的实现类(注解了 @Component)放到该 map 中。其中 key 就是 @Component 中指定的实例化服务的名称,value 便是对应的对象。
1 | java复制代码public class Test { |
借助枚举类进一步优化
我们再进一步改进。我们不再在策略角色类中调用策略类的方法了,只让策略角色类作为工厂的角色,返回对应的服务。而相关服务方法的调用由客户端直接调用实现类的方法。
同时,针对服务的名称和类型我们通过枚举进行映射。先来定义一个枚举类:
1 | java复制代码public enum TypeEnum { |
然后改造环境角色类为 SendMessageHandler:
1 | java复制代码@Component |
测试一下
1 | java复制代码public class Test { |
此时,如果新添加算法,只用创建对应算法的服务,然后在枚举类中映射一下关系,便可在不影响客户端调用的情况进行扩展。当然,根据具体的业务场景还可以进行进一步的改造。
总结
设计模式可以可以更好的扩展代码,但是一定程度上也加大了代码的阅读成本。所以在实际的项目中,不要一味的追求设计模式,要结合实际的业务情况进行合理的选择。当判断项固定且较少时,if…else… 也是一种更高效且便于维护的方式。
本文转载自: 掘金