首页 > 其他分享 >一文整合工厂模式、模板模式、策略模式

一文整合工厂模式、模板模式、策略模式

时间:2024-03-25 14:34:15浏览次数:28  
标签:一文 pay 接口 模式 PayParams 支付 public 模板 payParams

为什么使用设计模式

今天终于有时间系统的整理一下这几个设计模式了, 这几个真是最常用的,用好了它们,你就在也不用一大堆的if else 了。能更好的处理大量的代码冗余问题。

在我们的实际开发中,肯定会有这样的场景:我们的某个方法被多次重复调用,但是每次呢,还需要稍微的改动里面一部分的内容。但是我们常常的写法就是,既然能复用,那我就把原来的接口copy出来一份再改一该里面的内容。(哦,nice,真快,三下五除二解决)但是这样的代码其实就真的只是能运行,给后期运维会带来很大的压力。

倘若我们系统第一版本就这么开发完成了,到第二版需求迭代时。
老板说:“把某某某功能改一下,原来的逻辑统一变了,这个就小改动应该很快吧,给你半天时间。”
然后你说:“我靠,那这工作量太大了, 我每个接口都有这个代码,这一变动,就要全部修改,我点需要两天时间。”
老板说:“这么个破修改你要两天,别再这摸鱼了啊,半天肯定能完事,我自己都能改完, 半天改不完,baibai”
然后你默默翻到我的文章,周末两天连续加班,修改了所有代码,全用上了这套设计模式,以后老板给你估算半天修改时间, 你抢答说:“不用,一两个小时吧就够了”。哈哈哈

设计模式介绍

工厂模式(Factory Pattern)是一种创建型设计模式,用于创建对象的实例化逻辑与客户端代码的分离。在工厂模式中,通过工厂类封装实例化对象的过程,客户端代码不需要直接调用构造函数来实例化对象,而是通过工厂类来创建对象。这样可以提供更灵活性和可维护性,且符合开闭原则。工厂模式常见的几种形式包括简单工厂模式、工厂方法模式和抽象工厂模式。

模板模式(Template Pattern)是一种行为设计模式,用于定义算法的骨架,将可变部分延迟到子类中实现。在模板模式中,定义一个模板方法用于规定算法的流程,同时定义一些抽象方法或钩子方法,子类可以重写这些方法以定义具体实现。通过模板模式,可以避免重复的代码,并提供一个统一的算法框架。

策略模式(Strategy Pattern)是一种行为设计模式,用于定义一系列算法,并将每个算法封装成一个独立的策略对象,客户端可以根据需要在运行时选择算法。在策略模式中,算法之间可以互相替换,独立于客户端,并相互独立运行。策略模式可以提高代码的灵活性和复用性,同时符合开闭原则。

实战代码讲解

常规写法

我们就拿最简单最热门的业务,电商项目的支付功能来讲解。
首先我们创建一个支付的接口。

public interface WxPayService {
    void pay(PayParams payParams);
}

public interface AliPayService {
    void pay(PayParams payParams);
}

随便定义一下这个接口参数

@Data
public class PayParams {
    private String name;
}

然后像我们正常的Javaweb项目一样,创建正常的MVC三层结构。

public class WxPayServiceImpl implements PayService{
    // 实现接口中的方法
    @Override
    public void pay(PayParams payParams) {
        // TODO 第一步:检验一些数据参数是否合格

	// TODO 第二步:微信支付具体步骤

	// TODO 第三步:支付成功,进行一些回写、赋值、返回等等操作。
    }
}

public class AliPayServiceImpl implements PayService{
    // 实现接口中的方法
    @Override
    public void pay(PayParams payParams) {
        // TODO 第一步:检验一些数据参数是否合格

	// TODO 第二步:支付宝支付具体步骤

	// TODO 第三步:支付成功,进行一些回写、赋值、返回等等操作。
    }
}

最后再定义一个controller层,调用

@Autowired
private WxPayService wxPayService;

@Autowired
private AliPayService aliPayService;

@PostMapping(value = "/WxPay")
public ResponseResult pay(@RequestBody PayParams params) {
    wxPayService.pay(params);
    return ResponseResult.success();
}

@PostMapping(value = "/AliPay")
public ResponseResult pay(@RequestBody PayParams params) {
    aliPayService.pay(params);
    return ResponseResult.success();
}

这样是实现了我们的支付功能,一个微信支付,一个支付宝支付。但是我们会发现,这样写出来的代码,冗余非常多。

接下来我把这个业务代码修改为使用设计模式的格式。

设计模式后的代码

首先我们还是创建一个支付接口。

public interface PayService {
    void pay(PayParams payParams);
}

然后我们来,实现这个接口,因为我们目前就有两种支付方式,等项目后续升级肯定还会接入越来越多的支付方式,所以我们这里目前就要有两个实现类来实现这个接口, 以后可能更多。

image.png
观看上图我们有发现,在实际的业务逻辑中,其实每个支付的代码中的第一步和第三步都是一样的,所以我们可以把它抽离成一个模板。模板模式这就被使用了。代码如下:

public abstract class PayServiceAbstract implements PayService{
    // 实现接口中的方法
    @Override
    public void pay(PayParams payParams) {
        before(payParams);
        realPay(payParams);
        after(payParams);
    }

    // 把这个核心支付功能定义为抽象的方法,留给具体的策略实现类去实现。
    public abstract void realPay(PayParams payParams);

    // 支付之前、之后的操作在抽象类中就定义一个模板方法,
    // 只要掉用了这个抽象方法就自己有该模板可使用。
    public void before(PayParams payParams){
        System.out.println("支付前操作");
    }
    public void after(PayParams payParams){
        System.out.println("支付后操作");
    }
}

上面代码中,我们是用一个抽象类实现了接口,但是抽象还不是具体的实现,它只是固定了一个模板,接下来我们就要有每个支付方式自己的类去做具体的实现,这个也就是策略模式。对一个接口分别使用不同的策略来做不同的事。

支付宝支付的具体策略服务

@Service
public class AliPayServiceAbstractImpl extends PayServiceAbstract{
    @Override
    public void realPay(PayParams payParams) {
        System.out.println("支付宝支付处理中。。。。");
    }
}

微信支付的具体策略服务

@Service
public class WxPayServiceAbstractImpl extends PayServiceAbstract{
    @Override
    public void realPay(PayParams payParams) {
        System.out.println("微信支付处理中。。。。");
    }
}

ok,到目前,策略模式 + 模板模式就使用成功了,每当需求再叠加时,我们只需要再加一个具体的策略服务就ok了。别的地方都不需要动。

接下来时控制层的调用。我们如果还是用原来的controller,定义一个微信支付接口一个支付宝支付接口,那也太麻烦了。而且如果以后再有个银行卡支付,apple支付,那每次还要新增接口,真麻烦。所以我们不妨使用工厂模式来解决这个问题,让工厂来帮我们确定到底要用哪种支付。这样就来到了我们的工厂模式。

定义一个工厂

@Service
public class PayFactory {
	// payType 哪个具体策略服务
    public PayServiceAbstract getFactory(String payType){
        try {
            Class<?> aClass = Class.forName("com.bihe.controller."+payType);
            PayServiceAbstract payServiceAbstract = (PayServiceAbstract) aClass.getDeclaredConstructor().newInstance();
            return payServiceAbstract;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

上面的代码中,我们是用了Java反射,根据我们传递进来的类名,自动反射创建出具体的策略对象。

最后就是我们的控制层了。

@PostMapping(value = "/pay")
    public ResponseResult pay(@RequestBody PayParams params) {
        PayServiceAbstract payServiceAbstract = payFactory.getFactory(params.getName());
        payServiceAbstract.pay(params);
        return ResponseResult.success();
    }

这就非常简单了, 我们永远只用这一样接口,前端也不需要判断我什么时候调用weixin支付,什么时候调用ali支付…
前端可以一直调用这个一个接口就可以了,只是把响应支付的关键参数传递过来就可以了。

前端调用
image.png

image.png

标签:一文,pay,接口,模式,PayParams,支付,public,模板,payParams
From: https://blog.csdn.net/weixin_43741322/article/details/137013006

相关文章

  • MyBatisPlus新版代码生成器(Velocity模板引擎详解)
    文章目录一、Velocity模板引擎1、velocity简介2、快速入门3、基础语法4、注释5、变量6、循环7、条件8、引入资源9、macro宏二、MybatisPlus代码生成器1、MP代码生成器2、自定义velocity模板2.1、MybatisPlus自带模板和变量2.2、公共模板`common.vm`文件2.3、实体模板`en......
  • 一文彻底搞懂Redis底层数据结构
    文章目录1.数据结构与数据类型的关系2.底层数据结构详解2.1SDS:简单动态字符串2.2双端链表2.3压缩列表2.4哈希表2.5整数集合2.6跳表2.7quicklist2.8listpack1.数据结构与数据类型的关系Redis是一个基于内存的数据存储系统,它支持多种数据结构和数据类型,......
  • VS Code关闭受限模式(工作区信任)
    一、发生情况0.新安装了VSCode但是打开的时候插件没有启用,同时上方有提示1.打开VSCode提示目前处于限制模式下2.点击了解详细信息后阅读说明得知:在受限模式下vscode将禁用或限制任务、调试、工作空间设置和扩展,来提高安全性。二、解决方案1.网上查了一下,决定关闭这......
  • 一文让你读懂JavaScript原型对象与原型链的继承
    前言有些新手朋友可能听说过这么一句话,就是js中存在两个链条,它们分别为:作用域链和原型链它们彼此的区别在于作用域链是为了访问变量和数据而存在的一种链条访问机制而原型链是访问对象的属性或者方法而存在的一种机制!其中这里的原型链就是今天我要说的主题!我们学习js必须......
  • drf : web应用模式,RESTful API规范,接口测试工具:Postman
    drf:web应用模式,RESTfulAPI规范,接口测试工具:PostmanWeb应用模式前后端不分离前后端分离API接口前后端交互的媒介WebAPI接口和一般的url链接还是有区别的,WebAPI接口简单概括有下面四大特点。url:长得像返回数据的url链接https://api.map.baidu.com/place/v2/search......
  • 【前端素材】推荐优质多用途生活家具购物商城网站设计Glee平台模板(附源码)
    一、需求分析在线生活家具商店网站是指专门销售各类家具和家居用品的网上商店。这类网站提供用户浏览、选择并购买各种家具产品的平台。以下是在线生活家具商店网站的一般功能:产品展示与购买: 网站展示各种家具产品,如沙发、床、桌子、椅子、柜子等,用户可以查看详细信息、图......
  • 【前端素材】推荐优质多用途肉类品商城网站设计Meatza平台模板(附源码)
    一、需求分析多用途肉类品商城网页是一个在线平台,专门销售各种肉类及相关产品的电子商城。以下是这类网页通常具备的具体功能:产品分类:网页会根据不同种类的肉类进行分类,如牛肉、猪肉、禽类、海鲜等,方便用户查找所需产品。产品展示:网页会展示各种肉类产品的图片、价格、产......
  • 保护模式番外篇
    将ShellCode写入到0地址,通过函数指针指向NULL,来实现调用主要是为了理解共享内存。扣硬编码代码:charShell[]={ 0x6A,0, 0x6A,0, 0x6A,0, 0x6A,0, 0xb8,0,0,0,0, 0xff,0xd0, 0xc3};intmain(){ PVOIDmem=VirtualAlloc(0,0x100,MEM_COMMIT......
  • spark-shell(pyspark)单机模式使用和编写独立应用程序
    spark有四种部署方式:Local,Standalone,SparkonMesos,Sparkonyarn。第一个为单机模式,后三个为集群模式。spark-shell支持python和scala,这里使用python。1.启动pyspark环境在spark安装目录下./bin/pyspark进入之后,如下图: 2.编写程序新建代码文件WordCount.py,并编写程序......
  • C++ 设计模式
    C++设计模式工厂模式:我们需要方便的使用这些类,减少耦合度#include<iostream>#include<string>usingnamespacestd;classcar{public:car(stringname):name_(name){}virtualvoidshow();protected:stringname_;};classaodi:publiccar{public: aod......