前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一次代码优化实践,用了模板方法+策略+工厂方法模式

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

作者头像
捡田螺的小男孩
发布2020-09-27 20:44:29
2.1K0
发布2020-09-27 20:44:29
举报

前言

好久没分享工作总结啦,今天来一份代码优化总结。用模板方法+策略+工厂方法模式优化了代码,耐心点看完,应该对大家有帮助的~

优化代码前

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

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

代码语言:javascript
复制
// 商户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请求+验签,于是呢,可以直接把它们抽象成一个公用类呀~在这里就要引入模板方法模式咯

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

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

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

子类商户A实现:

代码语言:javascript
复制
CompanyAServiceImpl extends AbstractCompanyCommonService{
    Resp hander(req){
      return handlerTempPlate(req);
    }
    //公司A是走代理的
    boolean isRequestByProxy(){
       return true;
    }

子类商户B实现:

代码语言:javascript
复制
CompanyBServiceImpl extends AbstractCompanyCommonService{
    Resp hander(req){
      return handlerTempPlate(req);
    }
    //公司B是不走代理的
    boolean isRequestByProxy(){
       return false;
    }
策略模式

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

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

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

代码语言:javascript
复制
// 定义一个方法,把策略交给子类去实现。
interface ICompanyCommonService{
  Resp hander(req);
}

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

代码语言:javascript
复制
CompanyCServiceImpl extends AbstractCompanyCommonService{
    Res hander(req){
       //查询商户信息
       queryMerchantInfo();
       requestByWebservice();    
    }
    //随意了,你都不走模板了
    boolean isRequestByProxy(){
       return false;
    }
工厂方法模式

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

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

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

代码语言:javascript
复制
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;
    } 

工厂方法模式出炉咯:

代码语言:javascript
复制
@Component
public class CompanyServiceFactory implements ApplicationContextAware {

    private static Map<CompanyEnum, ICompanyCommonService> map = new HashMap<>();

    @Override
    public 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);
    }
}

最后建议

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

代码语言:javascript
复制
@Service
public class CompanyHandler implements RequestHandler  {
   @Autowire
   private CompanyServiceFactory companyServiceFactory;
   
   Resp hander(req){
    return companyServiceFactory.handler(req);
  }
}

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 捡田螺的小男孩 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 优化代码思路
      • 模板方法模式
      • 策略模式
      • 工厂方法模式
    • 最后建议
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档