[代码结构设计]根据不同条件使用不同实现类的业务代码设计
场景
此时有一个场景,需要设计一个根据不同的状态和条件采用不同的业务处理方式。
这样大家可能不是太理解。举个例子,现在大街小巷上的商户都采用了聚合支付的支付方式,聚合支付也就是商户柜台前放了一个支持支付宝、微信、京东钱包、银联等等的二维码,用户可以通过任意一款支付APP进行支付。
解决思路
思路①
对每个支付渠道进行定义枚举类型
public enum PayWay { ALI_PAY, WECHAT_PAY; }
然后在每个对应的service上定义注解,表示对应哪种支付方式
@Pay(PayWay.ALI_PAY) public class AliPayServiceImpl implements PayService {}
但是仔细思考后,还是存在一些问题
- 如果增加一个支付方式后还需要修改,
PayWay
这个枚举类型 - 在程序中,仍需要根据不同的条件做
if else
判断PayWay
,增加支付方式还是得修改原有的判断逻辑。伪代码如下
if("xxx" == "aliPay"){ } else if("xxx" == "wechatPay"){ } //如果增加支付方式还是得增加else if
思路②
在思路①中存在一些问题,首当其冲的就是if else
判断问题。先思考一下这个if else
的作用是什么?
答:根据思路①描述,这个if else
是用来确定采用哪种支付方式。
我们可以将这块代码抽离出来,让对应的业务实现类实现自己的逻辑实现,然后根据返回值true
或者false
决定是否过滤掉这个业务实现类。接口定义如下,SupportBean
是封装的一个实体
boolean isSupport(SupportBean supportBean);
然后在各个业务实现类都实现自己的isSupport方法,伪代码如下
@Override public boolean isSupport(SupportBean supportBean) { if (supportBean.getType() == "xxx"){ return true; } return false; }
设计
注:只提供一个架子
接口定义
Service接口定义,一个业务执行方法execute(参数自行添加),一个isSupport方法(返回true
或者false
)
public interface Service { void execute(); boolean isSupport(SupportBean supportBean); }
业务实现类
这里execute方法只是在控制台打印字符串。isSupport方法对SupportBean中的supportNum进行取余,判断余数是否等于0,是则返回true。
类似的实现还有两个,这里就不贴出来了。
@Component public class AServiceImpl implements Service { @Override public void execute() { System.out.println("A execute"); } @Override public boolean isSupport(SupportBean supportBean) { return supportBean.getSupportNum() % 3 == 0; } }
接下来在定义一个帮助类
帮助类
@Component public class Helper { @Autowired private List<Service> services; public void execute(SupportBean supportBean){ Service s = services.stream() .filter((service) -> service.isSupport(supportBean)) .findFirst()//NPE异常 .orElse(null); if (s != null){ s.execute(); } } }
通过工具类的execute方法来获取对应的业务实现类执行的结果,以及对传入的参数进行校验处理等。
需要注意的是Lambda表达式的findFirst()会出现NullPointException异常。因为filter对list进行过滤,会存在过滤完list的长度为0,如果此时在调用findFirst则会抛出NullPointException。可以将上面的代码修改为如下代码,这样就可以避免NPE了
Service s = services.stream() .filter((service) -> service.isSupport(supportBean)) .map(Optional::ofNullable) .findFirst() .flatMap(Function.identity()) .orElse(null);
测试
添加一个springboot测试类和一个测试方法。
在contextLoads测试中调用帮助类Helper的execute方法
@RunWith(SpringRunner.class) @SpringBootTest public class ApplicationTests { @Autowired private Helper Helper; @Test public void contextLoads() { Helper.execute(new SupportBean(3)); } }
测试结果
A execute
扩展
在Lambda表达式中是先将业务实现类进行过滤,然后获取第一个业务实现类并执行。
如果此时过滤存在多个业务实现类,而又不能确定优先级,这时需要如何进行扩展呢?
其实很简单,先在Service接口中定义一个getPriority
方法
int getPriority();
然后各自的实现类实现对应的getPriority
方法
接着修改Lambda表达式即可,在filter后增加sorted方法即可对业务实现类进行排序
Service s = services.stream() .filter((service) -> service.isSupport(supportBean)) .sorted(Comparator.comparing(Service::getPriority)) .map(Optional::ofNullable) .findFirst() .flatMap(Function.identity()) .orElse(null);
总结
整个大体框架基本都搭建完成,如需扩展只需要增加对应的业务实现类,而不用去修改其他类的代码。就连之前设计的枚举都可以不用,可扩展性大大提升。如需使用,只需修改对应的入参和对应的名称即可。
Github地址
如果对你有收获,欢迎star、欢迎fork
如果你也有类似的经验,欢迎加入,一起共建

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Django前后端分离实践之DRF--03
一、序列化 1. 创建表 以出版社的表为例子,例如出版社有名字和所属地区 选区_051 class Publisher(models.Model): name = models.CharField(max_length=32, verbose_name='名称', unique=True) address = models.CharField(max_length=128, verbose_name='地址') def __str__(self): return self.name class Meta: verbose_name = '出版社' verbose_name_plural = verbose_name 选区_162 2. 生成迁移文件和执行迁移 在这里我们暂时用sqlite数据库 python manage.py makemigrations python manage.py migrate 3. 什么是序列化 维基百科资料关于序列化的介绍 3.1 关于序列化的解释: 在程序运行的过程中,所有的变量都是在内存中,比如,定义一个dict: d = dict(name='Zh...
- 下一篇
Python正则表达式初识(九)
继续分享Python正则表达式的基础知识,今天给大家分享的特殊字符是[\u4E00-\u9FA5],这个特殊字符最好能够记下来,如果记不得的话通过百度也是可以一下子查到的。 该特殊字符是固定的写法,其代表的意思是汉字。换句话说,只要字符中是汉字,就可以通过该字符进行匹配,该特殊字符也是用中括号括起来的。具体的代码演示如下。 1、原始字符串是“加油”,两个汉字,然后将匹配模式直接为[\u4E00-\u9FA5],如下图所 可以看到此时的输出结果仅仅出现了一个“加”字,因为该匹配模式默认是匹配一个字符。 2、如何想匹配多个字符,只需要在匹配模式后面加一个“+”号即可,表示匹配连续出现的汉字,如下图所示。 此时可以看到“加油”全都匹配出来了。 3、为了进一步加强对该特殊字符的理解,现在将“加油”两字中嵌入非汉字,如下图所示。 可以看到只匹配到了“加”,但是非汉字字符“a”及其以后的字符全部都匹配不到了,因为原始字符串并不是连续出现的汉字。 4、将非汉字字符放到字符串最后边,如下图所示。 此时可以看到“加油”这两个连续的汉字可以成功匹配,但是非汉字字符匹配不到。 5、如果将“加油”中间加个空格...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,CentOS7官方镜像安装Oracle11G
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2全家桶,快速入门学习开发网站教程
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- MySQL8.0.19开启GTID主从同步CentOS8
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程