• 【设计模式】【第一章】【支付场景】【策略模式 + 工厂模式 + 门面模式 + 单例模式】


    创建design-demo项目

    项目代码:https://gitee.com/java_wxid/java_wxid/tree/master/demo/design-demo
    项目结构如下(示例):
    在这里插入图片描述

    修改pom.xml

    代码如下(示例):

    
    
        4.0.0
    
        
            org.springframework.boot
            spring-boot-starter-parent
            2.7.3
             
        
    
    
        com.example
        design-demo
        0.0.1-SNAPSHOT
        design-demo
        Demo project for Spring Boot
    
        
            1.8
            UTF-8
            UTF-8
            2.3.7.RELEASE
        
    
        
            
                org.springframework.boot
                spring-boot-starter
            
    
            
                org.springframework.boot
                spring-boot-starter-web
            
    
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
            
                org.springframework.statemachine
                spring-statemachine-core
                2.1.3.RELEASE
            
        
    
        
            
                
                    org.springframework.boot
                    spring-boot-maven-plugin
                
            
        
    
    
    
    

    传统模式开发

    创建PayController

    代码如下(示例):

    package com.example.designdemo.controller;
    
    import com.example.designdemo.pojo.PayBody;
    import com.example.designdemo.service.PayService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:26
     * @Description:
     */
    @RestController
    @RequestMapping("/pay")
    public class PayController {
    
        @Autowired
        private PayService payService;
    
        @PostMapping("/dopay")
        public Boolean dopay(@RequestBody PayBody payBody){
            return payService.pay(payBody);
        }
    
    }
    
    

    创建PayService

    代码如下(示例):

    package com.example.designdemo.service;
    
    import com.example.designdemo.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:28
     * @Description:
     */
    
    public interface PayService {
    
    
        Boolean pay(PayBody payBody);
    }
    
    

    创建PayServiceImpl

    代码如下(示例):

    package com.example.designdemo.service.impl;
    
    import com.example.designdemo.handler.PayHandler;
    import com.example.designdemo.pojo.PayBody;
    import com.example.designdemo.service.PayService;
    import org.springframework.stereotype.Service;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:29
     * @Description:
     */
    @Service
    public class PayServiceImpl implements PayService {
    
    
        @Override
        public Boolean pay(PayBody payBody) {
            //付款逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = PayHandler.zfbpay(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = PayHandler.wxbpay(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = PayHandler.bankbpay(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;
        }
    }
    
    

    创建PayBody

    代码如下(示例):

    package com.example.designdemo.pojo;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:29
     * @Description: 属性的类型这里都是简写,实战项目肯定不会写这么粗糙,这里主要是写设计模式相关,细节就不抠了。
     */
    
    public class PayBody {
        //账号
        private String account;
        //支付类型
        private int type;
        //产品信息
        private String product;
        //金额
        private int amcount;
    
        public String getAccount() {
            return account;
        }
    
        public void setAccount(String account) {
            this.account = account;
        }
    
        public int getType() {
            return type;
        }
    
        public void setType(int type) {
            this.type = type;
        }
    
        public String getProduct() {
            return product;
        }
    
        public void setProduct(String product) {
            this.product = product;
        }
    
        public int getAmcount() {
            return amcount;
        }
    
        public void setAmcount(int amcount) {
            this.amcount = amcount;
        }
    }
    
    

    创建PayHandler

    代码如下(示例):

    package com.example.designdemo.handler;
    
    import com.example.designdemo.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:42
     * @Description:
     */
    @Component
    public class PayHandler {
    
    
        public static boolean zfbpay(PayBody payBody) {
            //详细调用支付宝提供的第三方接口
            //........................
            return true;
        }
    
        public static boolean wxbpay(PayBody payBody) {
            //详细调用支付宝提供的第三方接口
            //........................
            return true;
        }
    
        public static boolean bankbpay(PayBody payBody) {
            //详细调用支付宝提供的第三方接口
            //........................
            return true;
        }
    }
    
    

    传统模式开发总结

    正常这段代码逻辑是没什么问题的,初中级这么写也没什么毛病。
    但是对于高级开发而言,就需要思考它的一个扩展性,封装性了,这里举个例子:
    假设PayServiceImpl.pay是由你来写的,PayHandler.zfbpay、PayHandler.wxbpay、PayHandler.bankbpay是由另外一个同事来写的,并且以jar包的形式集成到你的项目中,提供给你调用的。

    弊端:

    • PayServiceImpl.pay作为业务的调用端,需要掌握的信息比较多,需要知道PayHandler.zfbpay、PayHandler.wxbpay、PayHandler.bankbpay的接口入参和返回参数。
    • 调用方式比较繁琐,每个支付方式都要有一个方法调用,我们有更简洁的方式提供,比如传入参数PayHandler.pay(0 or 1 or 2)代表不同的支付方式
    • if else过多,不够优雅
    • 不太好扩展,只要引入一个新的支付方式,PayHandler那边新添加一个方法,那么PayServiceImpl.pay的代码就需要改动,对业务层的代码进行了修改,任何的代码改动都有可能导致之前的业务逻辑产生问题,比如代码合并覆盖,不小心多加了个字母等等,所以我们希望对业务层的代码能不做改动就尽量别去动业务层的代码
    • 接口不好迁移,假设后面架构师搭好了一套新的框架,需要把支付相关的接口迁移过去,这个时候就得把代码一块一块的迁移,调用逻辑全得看一遍,不能整个包复制粘贴过去,然后微调一下就实现接口迁移,比较费时。

    后面我们一步一步进行改造,最终的目标就是解决上述的问题

    引入策略模式

    首先对上述代码进行改造,先引入策略模式

    对PayServiceImpl进行改造

    代码如下(示例):

    package com.example.designdemo.service.impl;
    
    import com.example.designdemo.context.PayContext;
    import com.example.designdemo.handler.PayHandler;
    import com.example.designdemo.inter.BankPayStrategy;
    import com.example.designdemo.inter.WxPayStrategy;
    import com.example.designdemo.inter.ZfbPayStrategy;
    import com.example.designdemo.pojo.PayBody;
    import com.example.designdemo.service.PayService;
    import org.springframework.stereotype.Service;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:29
     * @Description:
     */
    @Service
    public class PayServiceImpl implements PayService {
    
    
        @Override
        public Boolean pay(PayBody payBody) {
    /*        //传统模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = PayHandler.zfbpay(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = PayHandler.wxpay(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = PayHandler.bankbpay(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;*/
    
            //引入策略模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = new PayContext(new ZfbPayStrategy()).execute(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = new PayContext(new WxPayStrategy()).execute(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = new PayContext(new BankPayStrategy()).execute(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;
        }
    }
    
    

    创建PayContext

    代码如下(示例):

    package com.example.designdemo.context;
    
    import com.example.designdemo.inter.PayStrategy;
    import com.example.designdemo.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:30
     * @Description: 起到承上启下的作用
     */
    
    public class PayContext {
    
        private PayStrategy payStrategy;
    
        public PayContext(PayStrategy payStrategy){
            this.payStrategy = payStrategy;
        }
    
        public Boolean execute(PayBody payBody){
            return this.payStrategy.pay(payBody);
        }
    
    }
    
    

    创建PayStrategy

    代码如下(示例):

    package com.example.designdemo.inter;
    
    import com.example.designdemo.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:23
     * @Description: 引入策略模式
     */
    
    public interface PayStrategy {
    
        //未来顶PayHandler里面的三个
        Boolean pay(PayBody payBody);
    
    }
    
    

    创建BankPayStrategy

    代码如下(示例):

    package com.example.designdemo.inter;
    
    import com.example.designdemo.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:25
     * @Description: 替换掉PayHandler.bankpay
     */
    
    public class BankPayStrategy implements PayStrategy{
    
    
        @Override
        public Boolean pay(PayBody payBody) {
            //支付细节省略
            return true;
        }
    }
    
    

    创建WxPayStrategy

    代码如下(示例):

    package com.example.designdemo.inter;
    
    import com.example.designdemo.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:25
     * @Description: 替换掉PayHandler.wxpay
     */
    
    public class WxPayStrategy implements PayStrategy{
    
    
        @Override
        public Boolean pay(PayBody payBody) {
            //支付细节省略
            return true;
        }
    }
    
    

    创建ZfbPayStrategy

    代码如下(示例):

    package com.example.designdemo.inter;
    
    import com.example.designdemo.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:25
     * @Description: 替换掉PayHandler.zfbpay
     */
    
    public class ZfbPayStrategy implements PayStrategy{
    
    
        @Override
        public Boolean pay(PayBody payBody) {
            //支付细节省略
            return true;
        }
    }
    
    

    引入策略模式总结

    弊端:

    • if else过多,不够优雅
    • 策略类数量增多,每个策略都是一个类,复用的可能性比较小,类数量增加了
    • 所以的策略类都需要对外暴露,调用方需要知道有哪些策略才可以决定使用哪个策略,封装性得不到保证。
    • 只要引入一个新的支付方式,就要创建一个XXXPayStrategy的策略类实现PayStrategy接口,PayServiceImpl.pay的代码还是需要改动,对业务层的代码进行了修改,任何的代码改动都有可能导致之前的业务逻辑产生问题,比如代码合并覆盖,不小心多加了个字母等等,所以我们希望对业务层的代码能不做改动就尽量别去动业务层的代码
    • 接口不好迁移,假设后面架构师搭好了一套新的框架,需要把支付相关的接口迁移过去,这个时候就得把代码一块一块的迁移,调用逻辑全得看一遍,不能整个包复制粘贴过去,然后微调一下就实现接口迁移,比较费时。
      优点:
    • 策略可以自由切换,只要实现了抽象策略,就可以自由的切换选择策略
    • 扩展性提升,在系统中添加一个策略,只需要添加一个策略类,实现抽象的策略接口就可以了,其他不作修改

    引入工厂模式

    创建pay目录

    创建PayContext

    代码如下(示例):

    package com.example.designdemo.pay.context;
    
    import com.example.designdemo.pay.pojo.PayBody;
    import com.example.designdemo.pay.strategy.PayStrategy;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:30
     * @Description: 起到承上启下的作用
     */
    
    public class PayContext {
    
        private PayStrategy payStrategy;
    
        public PayContext(PayStrategy payStrategy){
            this.payStrategy = payStrategy;
        }
    
        public Boolean execute(PayBody payBody){
            return this.payStrategy.pay(payBody);
        }
    
    }
    
    

    创建StrategyFactory

    代码如下(示例):

    package com.example.designdemo.pay.factory;
    
    import com.example.designdemo.pay.strategy.PayStrategy;
    import com.example.designdemo.pay.strategyEnum.StrategyEnum;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:53
     * @Description: 策略工厂 工厂类依靠策略枚举返回策略类 后面都不需要修改了,因为它是一个无状态的
     */
    
    public class StrategyFactory {
    
        public static PayStrategy getPayStrategy(StrategyEnum strategyEnum){
            PayStrategy payStrategy = null;
            try {
                payStrategy = (PayStrategy)Class.forName(strategyEnum.getValue()).newInstance();
            } catch (Exception e) {
                //异常信息打印
            }
            return payStrategy;
        }
    
    }
    
    

    创建PayBody

    代码如下(示例):

    package com.example.designdemo.pay.pojo;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:29
     * @Description: 属性的类型这里都是简写,实战项目肯定不会写这么粗糙,这里主要是写设计模式相关,细节就不抠了。
     */
    
    public class PayBody {
        //账号
        private String account;
        //支付类型
        private int type;
        //产品信息
        private String product;
        //金额
        private int amcount;
    
        public String getAccount() {
            return account;
        }
    
        public void setAccount(String account) {
            this.account = account;
        }
    
        public int getType() {
            return type;
        }
    
        public void setType(int type) {
            this.type = type;
        }
    
        public String getProduct() {
            return product;
        }
    
        public void setProduct(String product) {
            this.product = product;
        }
    
        public int getAmcount() {
            return amcount;
        }
    
        public void setAmcount(int amcount) {
            this.amcount = amcount;
        }
    }
    
    

    创建PayStrategy

    代码如下(示例):

    package com.example.designdemo.pay.strategy;
    
    
    import com.example.designdemo.pay.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:23
     * @Description: 引入策略模式
     */
    
    public interface PayStrategy {
    
        //未来顶PayHandler里面的三个
        Boolean pay(PayBody payBody);
    
    }
    
    

    创建BankPayStrategy

    代码如下(示例):

    package com.example.designdemo.pay.strategy;
    
    import com.example.designdemo.pay.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:25
     * @Description: 替换掉PayHandler.bankpay
     */
    
    public class BankPayStrategy implements PayStrategy {
    
    
        @Override
        public Boolean pay(PayBody payBody) {
            //支付细节省略
            return true;
        }
    }
    
    

    创建WxPayStrategy

    代码如下(示例):

    package com.example.designdemo.pay.strategy;
    
    import com.example.designdemo.pay.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:25
     * @Description: 替换掉PayHandler.wxpay
     */
    
    public class WxPayStrategy implements PayStrategy {
    
    
        @Override
        public Boolean pay(PayBody payBody) {
            //支付细节省略
            return true;
        }
    }
    
    

    创建ZfbPayStrategy

    代码如下(示例):

    package com.example.designdemo.pay.strategy;
    
    import com.example.designdemo.pay.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:25
     * @Description: 替换掉PayHandler.zfbpay
     */
    
    public class ZfbPayStrategy implements PayStrategy {
    
    
        @Override
        public Boolean pay(PayBody payBody) {
            //支付细节省略
            return true;
        }
    }
    
    

    创建StrategyEnum

    代码如下(示例):

    package com.example.designdemo.pay.strategyEnum;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:56
     * @Description: 准备使用反射
     */
    
    public enum StrategyEnum {
    
        ZfbPayStrategy("com.example.designdemo.pay.strategy.ZfbPayStrategy"),
        WxPayStrategy("com.example.designdemo.pay.strategy.WxPayStrategy"),
        BankPayStrategy("com.example.designdemo.pay.strategy.BankPayStrategy");
    
        String value = "";
    
        StrategyEnum(String value){
            this.value = value;
        }
    
        public String getValue(){
            return this.value;
        }
    }
    
    

    改造PayServiceImpl

    代码如下(示例):

    package com.example.designdemo.service.impl;
    
    //import com.example.designdemo.context.PayContext;
    //import com.example.designdemo.handler.PayHandler;
    //import com.example.designdemo.inter.BankPayStrategy;
    //import com.example.designdemo.inter.WxPayStrategy;
    //import com.example.designdemo.inter.ZfbPayStrategy;
    //import com.example.designdemo.pojo.PayBody;
    import com.example.designdemo.pay.context.PayContext;
    import com.example.designdemo.pay.factory.StrategyFactory;
    import com.example.designdemo.pay.strategyEnum.StrategyEnum;
    
    import com.example.designdemo.pay.pojo.PayBody;
    import com.example.designdemo.service.PayService;
    import org.springframework.stereotype.Service;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:29
     * @Description:
     */
    @Service
    public class PayServiceImpl implements PayService {
    
    
        @Override
        public Boolean pay(PayBody payBody) {
    /*        //传统模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = PayHandler.zfbpay(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = PayHandler.wxpay(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = PayHandler.bankbpay(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;*/
    
    /*        //引入策略模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = new PayContext(new ZfbPayStrategy()).execute(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = new PayContext(new WxPayStrategy()).execute(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = new PayContext(new BankPayStrategy()).execute(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;*/
    
            //引入工厂模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = new PayContext(StrategyFactory.getPayStrategy(StrategyEnum.ZfbPayStrategy)).execute(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = new PayContext(StrategyFactory.getPayStrategy(StrategyEnum.WxPayStrategy)).execute(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = new PayContext(StrategyFactory.getPayStrategy(StrategyEnum.BankPayStrategy)).execute(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;
        }
    }
    
    
    

    改造PayService

    代码如下(示例):

    package com.example.designdemo.service;
    
    //import com.example.designdemo.pojo.PayBody;
    
    import com.example.designdemo.pay.pojo.PayBody;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:28
     * @Description:
     */
    
    public interface PayService {
    
    
        Boolean pay(PayBody payBody);
    }
    
    

    改造PayController

    代码如下(示例):

    package com.example.designdemo.controller;
    
    //import com.example.designdemo.pojo.PayBody;
    import com.example.designdemo.pay.pojo.PayBody;
    import com.example.designdemo.service.PayService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:26
     * @Description:
     */
    @RestController
    @RequestMapping("/pay")
    public class PayController {
    
        @Autowired
        private PayService payService;
    
        @PostMapping("/dopay")
        public Boolean dopay(@RequestBody PayBody payBody){
            return payService.pay(payBody);
        }
    
    }
    
    

    引入策略模式 + 工厂模式总结

    缺点:

    • 有点金玉其内败絮其外的意思,业务层调用还是那么烂
      优点:
    • 内部封装的特别好,全部封装到pay目录下,没有依赖外部,可以直接打包
    • 方便迁移接口,扩展性好,所有逻辑都封装在pay目录下面,可以直接整个pay目录复制到其他下面实现迁移

    引入门面模式

    创建StrategyFacade

    代码如下(示例):

    package com.example.designdemo.pay.facade;
    
    import com.example.designdemo.pay.context.PayContext;
    import com.example.designdemo.pay.strategy.PayStrategy;
    import com.example.designdemo.pay.factory.StrategyFactory;
    import com.example.designdemo.pay.pojo.PayBody;
    import com.example.designdemo.pay.strategyEnum.StrategyEnum;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 11:27
     * @Description: 门面模式,最终只暴露门面即可,门面就是我们的超级封装
     */
    
    public class StrategyFacade {
    
        public static Boolean pay(PayBody payBody){
            //获取策略枚举
            StrategyEnum strategyEnum = getStrategyEnum(payBody.getType());
            //获取策略对象
            PayStrategy payStrategy = StrategyFactory.getPayStrategy(strategyEnum);
            //生成策略上下文
            PayContext payContext = new PayContext(payStrategy);
            //进行付款
            Boolean execute = payContext.execute(payBody);
            return execute;
        }
    
        private static StrategyEnum getStrategyEnum(int type) {
            switch (type){
                case 0:
                    return StrategyEnum.ZfbPayStrategy;
                case 1:
                    return StrategyEnum.WxPayStrategy;
                case 2:
                    return StrategyEnum.BankPayStrategy;
                default:
                    return null;
            }
        }
    
    }
    
    

    改造PayServiceImpl

    代码如下(示例):

    package com.example.designdemo.service.impl;
    
    //import com.example.designdemo.context.PayContext;
    //import com.example.designdemo.handler.PayHandler;
    //import com.example.designdemo.inter.BankPayStrategy;
    //import com.example.designdemo.inter.WxPayStrategy;
    //import com.example.designdemo.inter.ZfbPayStrategy;
    //import com.example.designdemo.pojo.PayBody;
    import com.example.designdemo.pay.context.PayContext;
    import com.example.designdemo.pay.facade.StrategyFacade;
    import com.example.designdemo.pay.factory.StrategyFactory;
    import com.example.designdemo.pay.strategyEnum.StrategyEnum;
    
    import com.example.designdemo.pay.pojo.PayBody;
    import com.example.designdemo.service.PayService;
    import org.springframework.stereotype.Service;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 9:29
     * @Description:
     */
    @Service
    public class PayServiceImpl implements PayService {
    
    
        @Override
        public Boolean pay(PayBody payBody) {
    /*        //传统模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = PayHandler.zfbpay(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = PayHandler.wxpay(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = PayHandler.bankbpay(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;*/
    
    /*        //引入策略模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = new PayContext(new ZfbPayStrategy()).execute(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = new PayContext(new WxPayStrategy()).execute(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = new PayContext(new BankPayStrategy()).execute(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;*/
    
    /*        //引入工厂模式开发支付逻辑
            boolean flag = false;
            int type = payBody.getType();
            if (type == 0) {
                //支付宝支付逻辑
                flag = new PayContext(StrategyFactory.getPayStrategy(StrategyEnum.ZfbPayStrategy)).execute(payBody);
            }else if(type == 1){
                //微信支付逻辑
                flag = new PayContext(StrategyFactory.getPayStrategy(StrategyEnum.WxPayStrategy)).execute(payBody);
            }else if(type == 2){
                //银行卡支付逻辑
                flag = new PayContext(StrategyFactory.getPayStrategy(StrategyEnum.BankPayStrategy)).execute(payBody);
            }else {
                throw new UnsupportedOperationException("unsupport type,please choose o,1,2 ");
            }
    
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;*/
    
            //引入门面模式开发支付逻辑
            Boolean flag = StrategyFacade.pay(payBody);
            if (flag) {
                //支付成功走后续逻辑
            }
            return flag;
        }
    }
    
    

    策略模式 + 工厂模式 + 门面模式总结

    优点:

    • 将来我们删除或者增加或者修改任何关于付款的模块,无需改动service。
    • 不会对调用层产生任何代码的改动。
    • 调用层使用我们的pay 模块,无需关心实现的逻辑,只需要将入参传给我们的pay模块即可。
    • 避免使用多重条件判断,扩展性,封装性,灵活性,安全性良好,简洁,易维护,易迁移
      缺点:
    • 策略类变多
    • 需要修改门面角色代码
    • StrategyFactory.getPayStrategy每次调用都需要进行一次反射,需要优化调整。

    引入单例模式

    对StrategyFactory进行调整

    代码如下(示例):

    package com.example.designdemo.pay.factory;
    
    import com.example.designdemo.pay.strategy.PayStrategy;
    import com.example.designdemo.pay.strategyEnum.StrategyEnum;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @Author: zhiwei Liao
     * @Date: 2022/9/25 10:53
     * @Description: 策略工厂 工厂类依靠策略枚举返回策略类 后面都不需要修改了,因为它是一个无状态的 使用饿汉单例模式创建
     */
    
    public class StrategyFactory {
    
        private static final Map strategyMaps = new ConcurrentHashMap();
    
        public static PayStrategy getPayStrategy(StrategyEnum strategyEnum){
            PayStrategy payStrategy = strategyMaps.get(strategyEnum.getValue());
            try {
                payStrategy = (PayStrategy) Class.forName(strategyEnum.getValue()).newInstance();
                strategyMaps.put(strategyEnum.getValue(), payStrategy);
            } catch (Exception e) {
                //异常信息打印
            }
            return payStrategy;
        }
    
    }
    
    

    这里没有使用传统的单例模式,我需要在StrategyFactory里面获取PayStrategy所有的类型,所以这里面使用了一个map进行存储,同时为了保证线程安全使用ConcurrentHashMap保证线程安全。

    传统的单例模式:
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    单例模式的优点:

    • 内存中只有一个实例,减少内存开支,避免对象频繁创建、销毁
    • 一个对象的产生需要比较多的资源,比如读取配置,依赖其他对象等等,使用单例模式只生成一个实例,可以在应用启动的时候直接产生一个单例对象,然后用永久驻留内存的方式来解决性能问题,减少性能开销。
    • 避免对资源多重占用,比如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件同时写操作。
    • 可以设置系统全局访问点,优化共享资源访问,比如可以设计一个单例类,负责所有数据表的映射。

    引入单例模式,解决了策略模式 + 工厂模式 + 门面模式中StrategyFactory.getPayStrategy每次调用都需要进行一次反射创建对象。

    最后我们的项目结构如下(示例):(仅展开的类有用到)

    在这里插入图片描述

  • 相关阅读:
    Kibana:创建你的第一个仪表板
    成为比开发更硬气的测试人,我都经历了什么?
    HCIA-R&S自用笔记(26)PPP
    SpringMVC笔记
    Codejock Toolkit工具包专业版
    前端进击笔记第十九节 Angular,React,Vue 三大前端框架的设计特色
    【节能学院】安科瑞餐饮油烟监测云平台助力大气污染攻坚战
    Kotlin中Any、Nothing、Unit 类型的概念和用法
    快解析助力解决局域网打印难题
    隐写术——PNG文件隐藏payload
  • 原文地址:https://blog.csdn.net/java_wxid/article/details/127034541