优化代码前

先来了解一下类似的业务场景,简言之,就是:多个商户接入我们系统,都是走一个类似的流程通过http请求出去的。

优化前,每个公司对应一个句柄服务,伪代码如下:

// 商户A处理句柄
CompanyAHandler implements RequestHandler {Resp hander(req){//查询商户信息queryMerchantInfo();//加签signature();// http请求(走代理)httpRequestbyProxy()// 验签verify();}
}
// 商户B处理句柄
CompanyBHandler implements RequestHandler {Resp hander(Rreq){//查询商户信息queryMerchantInfo();//加签signature();// http请求(不走代理)httpRequestbyDirect();// 验签verify(); }
}
// 商户C处理句柄
CompanyBHandler implements RequestHandler {Resp hander(Rreq){//查询商户信息queryMerchantInfo();// webservice 方式调用requestByWebservice();}
}

 

 

优化代码思路

我的优化代码思路,是有「重复代码,先把它抽出来,或者公用变量,或者公用方法,伸着公用类」。所以呢,查询商户信息呀,加签呀,http请求呀先全部各抽成一个公用方法。你细心点会发现,连每个Handler处理过程都很类似的,大概都是查询商户信息+加签+http请求+验签,于是呢,可以直接把它们抽象成一个公用类呀~在这里就要引入模板方法模式咯

模板方法模式

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
这种类型的设计模式属于行为型模式。

既然每个Handler处理,都是类似的流程,那「定义一个抽象类,把查询商户信息,加签,http请求,验签什么的,都放到里面去,俨然一个模板一样」。然后,因为有些商户走http代理,有些又没走代理,怎么办呢? 定义「一个抽象方法,给子类实现」嘛,因为能共用就放到父类(当前的抽象类),不能共用就放到子类嘛~代码如下:

abstract class AbstractCompanyCommonService implements ICompanyCommonService { //模板方法Resp handlerTempPlate(req){//查询商户信息queryMerchantInfo();// 加签signature();//http 请求if(isRequestByProxy()){httpProxy();}else{httpDirect();}// 验签verifySinature();}// Http是否走代理abstract boolean isRequestByProxy();
}

子类商户A实现:

CompanyAServiceImpl extends AbstractCompanyCommonService{Resp hander(req){return handlerTempPlate(req);}//公司A是走代理的boolean isRequestByProxy(){return true;}

子类商户B实现:

CompanyBServiceImpl extends AbstractCompanyCommonService{Resp hander(req){return handlerTempPlate(req);}//公司B是不走代理的boolean isRequestByProxy(){return false;}

策略模式

心细的读者会发现,甚至提出疑问,「你的商户C的服务实现跟你定义的公用模板,不太一样呢」,那当然,实际开发中,不跟你定义的模板一样太常见了,需求是产品提的嘛,又不是根据你模板提的,是代码服务于需求的。好了,不多说啦,我使用了策略模式,来优化这个问题。

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

策略模式理解起来其好抽象对不对?我个人理解,其实策略模式就是定义一个方法(所谓算法),给子类自己去实现。实际上就是「定义个方法/接口,让子类自己去实现」。看代码吧:

// 定义一个方法,把策略交给子类去实现。
interface ICompanyCommonService{Resp hander(req);
}

前面商户A和商户B还是不变,使用抽象类AbstractCompanyCommonService的模板,模板不满足商户C,商户C只能自己去实现咯,各个子类自己去实现的行为,就是策略模式的体现呢,如下:

CompanyCServiceImpl extends AbstractCompanyCommonService{Res hander(req){//查询商户信息queryMerchantInfo();requestByWebservice();    }//随意了,你都不走模板了boolean isRequestByProxy(){return false;}

工厂方法模式

商户A、B、C服务怎么被管理呢,之前分别给A,B,C服务实现handler的,现在好了,都不知道怎么管理了,怎么知道调用哪个呢?别慌,解决方案是「工厂方法模式」

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

工厂方法模式具体实现就是:接口定义一个枚举,每个服务实现都重新实现枚举,设置唯一标志枚举,再交给spring容器管理。看代码咯:

interface ICompanyCommonService{Resp hander(req);CompanyEnum getCompanyEnum();
}CompanyAServiceImpl extends AbstractCompanyCommonService{Resp hander(req){return handlerTempPlate(req);}//公司A是走代理的boolean isRequestByProxy(){return true;}CompanyEnum getCompanyEnum(){return CompanyEnum.A;} CompanyBServiceImpl extends AbstractCompanyCommonService{Resp hander(req){return handlerTempPlate(req);}//公司B是不走代理的boolean isRequestByProxy(){return false;}CompanyEnum getCompanyEnum(){return CompanyEnum.B;}

来来来,工厂方法模式出炉咯:

@Component
public class CompanyServiceFactory implements ApplicationContextAware {private static Map<CompanyEnum, ICompanyCommonService> map = new HashMap<>();@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {Map<String, ICompanyCommonService> tempMap = applicationContext.getBeansOfType(ICompanyCommonService.class);tempMap.values().forEach(iCompanyCommonService ->map.put(iCompanyCommonService.getCompanyEnum(), iCompanyCommonService));}public Resp handler(req) {return map.get(CompanyEnum.getCompanyEnum(req.getCompanyFlag()).hander(req);}
}

 

 

最后建议

最后,不要为了使用设计模式生搬硬套,而是优化代码过程中,发现这个设计模式刚好适用,才去用的哈。附上最后的代码咯:

@Service
public class CompanyHandler implements RequestHandler  {@Autowireprivate CompanyServiceFactory companyServiceFactory;Resp hander(req){return companyServiceFactory.handler(req);}
}

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

一次代码优化实践,用了模板方法+策略+工厂方法模式相关推荐

  1. 设计模式-策略模式,观察者模式,装饰者模式,静态工厂模式,工厂方法模式

    设计模式这个东西,永远不是单单从书本上就能获取到的东西.曾经看到一个比喻,比喻的就很巧妙,文艺复兴时期的教学方式,那时候诞生了很多巨匠,达芬奇,莫开朗基罗,拉斐尔都是在这个时期绽放光芒的巨星.有一种说 ...

  2. 设计模式 工厂方法_使用工厂方法模式设计最佳实践

    设计模式 工厂方法 在前面的"设计模式"示例中,我们解释了当今常用的"工厂"模式. 在本节中,我们将了解具有更多抽象的更高级的解决方案. 该模式称为工厂方法设计 ...

  3. 使用工厂方法模式设计最佳实践

    在前面的"设计模式"示例中,我们解释了当今常用的"工厂"模式. 在本节中,我们将了解具有更多抽象的更高级的解决方案. 该模式称为工厂方法设计模式. 定义: Fa ...

  4. 设计模式之工厂方法模式、抽象工厂模式的概念和实现及使用“反射技术+读取配置文件”的方法对工厂模式进行改进(软件工程综合实践课程第三周个人作业)

    文章目录 一.实验目的 二.知识总结 1.工厂方法模式简介 2.抽象工厂模式简介 3.工厂模式小结 4.利用"反射技术+读取配置文件"的方法改进程序 三.实验内容 1. 工厂模式实 ...

  5. Java 策略模式+工厂方法模式搭配思想

    策略模式 策略模式主要用于减少大量得if else得判断,适用场景即面对特定的环境下需要做特定的事.比如不同的VIP等级的优惠力度不同,那么一个VIP等级可以理解为一个特定的环境,对应的优惠力度可以理 ...

  6. 混合模式:工厂方法模式+策略模式

    通过下面这个实例对组合方法进行分析:某公司"一卡通"联机交易子系统,类似于银行的交易系统. IC卡上有以下两种金额: 固定金额:员工不能提现的金额,只能用来特定消费,如食堂内吃饭. ...

  7. java-抽象工厂模式+工厂方法模式+策略模式简单应用实战(登录场景)

    前言 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性. 设计模式 ...

  8. 混合模式(工厂方法模式+策略模式+门面模式)

    混合模式(工厂方法模式+策略模式+门面模式) 使用这三种模式设计一个简单的计算器程序:计算器是用于计算数值之间进行数学计算后所获得的值.它包含基本的"加减"功能.以上对以上需求进行 ...

  9. 【设计模式实践笔记】第一节:工厂方法模式

    前言 工作有段时间了,一直没有把自己所知所想沉淀下来,想趁着重新学习设计模式的机会,记录一些自己的心得体会. 大学里也有学过设计模式,那会没有实际的项目经验,感触不是很深,工作以后跟人讨论设计模式,有 ...

最新文章

  1. [转]Chrome 控制台console的用法
  2. setwindowpos怎么改变z序_置顶窗口SetWindowPos()的用法
  3. HDU5593 ZYB's Tree 树形DP +分治
  4. C++和C#编写调用COM组件
  5. HDU 6631 line symmetric(枚举)
  6. shiro会话监听_SpringBoot集成Shiro会话管理
  7. TensorFlow 之快速上手详解
  8. 【Kafka】Kafka 修改某个消费组的偏移量
  9. Android进阶:框架打造之IOC框架
  10. Uva 12657 Boxes in a Line 双向链表
  11. BlockingQueue的核心方法
  12. MAYA安装包+安装教程
  13. 【Java】PAT乙级真题全记录(二)21到40题
  14. 软件工程教程:第3章需求分析 课后习题
  15. 愚人节html源码,开源中国愚人节网页变模糊的js blur代码
  16. css3动画实现3d旋转效果
  17. 我的Hadoop安装流程
  18. 大前端养成之路:学一点MongoDB(一)
  19. Pycharm完整中文教程
  20. 仿网易蜗牛读书小程序

热门文章

  1. redis存储新闻列表_AWS上的Redis 数据存储服务_Redis云数据存储-AWS云服务
  2. onenote 思维导图_学生党做笔记,我为什么更推荐OneNote?看后你就明白了
  3. 虚拟机机操作系统已禁用 cpu。请关闭或重置虚拟机。_黑科技教学丨Win10竟然内置了一台虚拟机?教你如何玩转它...
  4. mysql 不限定 ip_mysql 不指定 ip 的连接默认都是 localhost
  5. C语言获取某个文件中一行内容中指定字符串后的值
  6. 关于android 自定义TitleBar 会遇到的问题
  7. 3-2:类与对象上篇——类的对象模型和计算类的大小以及this指针问题
  8. poj1789 Truck History(最小生成树)
  9. zenmap工具说明及常用参数解释
  10. 关于进程资源限制的getrlimit和setrlimit函数(epoll、服务器经常用)