策略模式+工厂模式

策略(Strategy)和工厂(Factory)是两种常见的设计模式,它们在不同的设计情景下可带来不同的好处
 

这两者也可以结合使用,以便在软件设计中提供更灵活且可维护的解决方案

工厂模式(Factory Pattern)
 

工厂模式是用于创建对象的模式,而不需要暴露对象创建的逻辑给客户端。在工厂方法模式中,一个方法返回一个对象,这个对象通常基于接口或抽象类。使用工厂模式意味着当你添加一个新的类(在这个场景中,新的支付服务)时,你不需要修改调用代码,只需修改工厂类即可。

PayChannelServiceFactory 在这个场景中就扮演了工厂的角色,根据给定的支付渠道(PayChannel),选择并返回正确的支付服务实现。
 

@Service
public class PayChannelServiceFactory {

    @Autowired
    private final Map<String, PayChannelService> serviceMap = new ConcurrentHashMap<String, PayChannelService>();

    public PayChannelService get(PayChannel payChannel) {

        String beanName = BeanNameUtils.getBeanName(payChannel.name(), "PayChannelService");

        //组装出beanName,并从map中获取对应的bean
        PayChannelService payChannelService = serviceMap.get(beanName);

        if (payChannelService != null) {
            return payChannelService;
        } else {
            throw new UnsupportedOperationException(
                    "No PayChannelService Found With payChannel : " + payChannel);
        }
    }
}


 

这里面借助了@Autowired注解,他可以把所有的PayChannelService的实现全部都注入到这个serviceMap里面,把bean name当做map的key,value就是对应的bean的实例。


 

策略模式(Strategy Pattern)

策略模式定义了一系列的算法或策略,并将它们封装起来,使得它们可以相互替换,且算法的变化不会影响到使用算法的客户端。这个模式的关键是定义一个策略接口,然后创建实现该接口的具体策略类。


 

在 PayChannelServiceFactory 中,PayChannelService 就是一个策略接口,而不同的支付渠道(如支付宝、微信等)的具体实现类就是不同的策略。利用工厂,根据传入的参数(在这里是 PayChannel)来选择使用哪个策略。

public interface PayChannelService {
    /**
     * 支付
     * @param payChannelRequest
     * @return
     */
    PayChannelResponse pay(PayChannelRequest payChannelRequest);

    /**
     * 支付结果回调
     * @param request
     * @param response
     */
    boolean nofity(HttpServletRequest request, HttpServletResponse response);
}
@Service("mockPayService")
@Slf4j
public class MockPayChannelServiceImpl implements PayChannelService {
    @Override
    public PayChannelResponse pay(PayChannelRequest payChannelRequest) {
        return null;
    }

    @Override
    public boolean nofity(HttpServletRequest request, HttpServletResponse response) {
        return true;
    }
}
@Service("wechatPayChannelService")
@Slf4j
public class WxPayChannelServiceImpl implements PayChannelService {
    @Autowired
    WxPayBean wxPayBean;

    @Autowired
    private PayApplicationService payApplicationService;

    String serialNo;
    @Override
    public PayChannelResponse pay(PayChannelRequest payChannelRequest) {
        WxPayChannelResponse resp=new WxPayChannelResponse();

        try {
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                .setAppid(wxPayBean.getAppId())
                .setMchid(wxPayBean.getMchId())
                .setDescription(payChannelRequest.getDescription())
                .setOut_trade_no(payChannelRequest.getOrderId())
                .setTime_expire(timeExpire)
                //附加数据,暂时先设置为与商品信息一致
                .setAttach(payChannelRequest.getAttach())
                .setNotify_url(wxPayBean.getDomain().concat("/wxPay/payNotify"))
                .setAmount(new Amount().setTotal(Integer.valueOf(String.valueOf(payChannelRequest.getAmount()))));

            log.info("request {}", JSONUtil.toJsonStr(unifiedOrderModel));
            IJPayHttpResponse response = WxPayApi.v3(
                RequestMethodEnum.POST,
                WxDomainEnum.CHINA.toString(),
                BasePayApiEnum.NATIVE_PAY.toString(),
                wxPayBean.getMchId(),
                getSerialNumber(),
                null,
                wxPayBean.getKeyPath(),
                JSONUtil.toJsonStr(unifiedOrderModel),
                AuthTypeEnum.RSA.getCode()
            );
            log.info("response {}", response);
            // 根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifySignature(response, wxPayBean.getPlatformCertPath());
            log.info("verifySignature: {}", verifySignature);
            String body=response.getBody();
            Map bodyMap=JSON.parseObject(body,Map.class);
            resp.setPayUrl(bodyMap.get("code_url").toString());
            resp.setSuccess(true);
            return resp;
        } catch (Exception e) {
            log.error("pay error ", e);
            resp.setSuccess(false);
            return resp;
        }
    }

    @Override
    public boolean nofity(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            log.info("支付通知密文 {}", result);

            // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                wxPayBean.getApiKey3(), wxPayBean.getPlatformCertPath());

            log.info("支付通知明文 {}", plainText);
            if (StrUtil.isEmpty(plainText)) {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }

            WxNotifyEntity wxNotifyEntity = JSON.parseObject(plainText, WxNotifyEntity.class);

            PaySuccessEvent paySuccessEvent = new PaySuccessEvent();
            paySuccessEvent.setChannelStreamId(wxNotifyEntity.getTransaction_id());
            paySuccessEvent.setPaidAmount(MoneyUtils.centToYuan(Long.valueOf(wxNotifyEntity.getAmount().total())));
            paySuccessEvent.setPayOrderId(wxNotifyEntity.getOut_trade_no());
            paySuccessEvent.setPaySucceedTime(DateUtil.parseUTC(wxNotifyEntity.getSuccess_time()));

            boolean paySuccessResult = payApplicationService.paySuccess(paySuccessEvent);

            if(paySuccessResult){
                response.setStatus(200);
                map.put("code", SUCCESS.name());
                map.put("message", SUCCESS.name());
            }else{
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "内部处理失败");
            }

            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            log.error("nofity error", e);
            return false;
        }
        return true;
    }

    private String getSerialNumber() {
        if (StrUtil.isEmpty(serialNo)) {
            // 获取证书序列号
            X509Certificate certificate = PayKit.getCertificate(wxPayBean.getCertPath());
            if (null != certificate) {
                serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
                // 提前两天检查证书是否有效
                boolean isValid = PayKit.checkCertificateIsValid(certificate, wxPayBean.getMchId(), -2);
                log.info("cert is valid {} effectiveTime {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
            }
        }
        System.out.println("serialNo:" + serialNo);
        return serialNo;
    }
}

策略+工厂的组合使用
 

将策略模式和工厂模式结合起来使用时,策略模式定义了操作的策略或行为,而工厂模式负责根据情况实例化具体的策略对象。

  1. 定义策略接口:定义一个PayChannelService接口,规定了所有支持的支付服务共同的操作。
  2. 实现策略接口:为每种支付方式实现一个具体的策略类,比如AlipayChannelService、WechatPayChannelService等。
  3. 创建工厂类:实现一个工厂类PayChannelServiceFactory。该工厂类拥有一个方法,能根据不同的输入(在这个例子中是PayChannel),返回对应的策略实现对象。


 

这种方式的优点是,当新增支付渠道或者修改现有渠道的支付逻辑时,你只需要添加或修改具体的策略实现类,而不需要修改调用这些策略的代码。这样,代码的维护性和扩展性都得到了提高,同时也保证了低耦合和高内聚的设计原则。

好的,我了解了您的问题。下面是我对这个问题的回答: 首先,我们需要了解一下策略模式工厂模式和模板方法模式的概念和用法: - 策略模式:将一组算法封装起来,使它们可以互相替换,从而使得算法的变化不会影响到使用算法的客户端。在策略模式中,我们需要定义一个策略接口和具体的策略实现类。 - 工厂模式:将对象的创建与使用分离,通过工厂类来创建对象,从而使得客户端无需知道对象的具体实现。在工厂模式中,我们需要定义一个工厂接口和具体的工厂实现类。 - 模板方法模式:将一组相似的算法步骤封装起来,使得算法的变化只会影响到模板方法的具体实现,从而使得代码的复用性和可维护性更好。 在实现不同支付方式的接口时,我们可以使用策略模式来实现不同的支付策略,工厂模式来创建不同的支付策略对象,模板方法模式来实现支付的公共流程。 具体实现步骤如下: 1. 定义支付策略接口 PaymentStrategy,其中包含一个 pay 方法用来实现支付功能。 ```java public interface PaymentStrategy { void pay(double amount); } ``` 2. 定义具体的支付策略实现类,例如 AlipayPaymentStrategy 和 WechatPaymentStrategy,实现 PaymentStrategy 接口中的 pay 方法。 ```java public class AlipayPaymentStrategy implements PaymentStrategy { @Override public void pay(double amount) { // 实现支付宝支付逻辑 System.out.println("使用支付宝支付:" + amount + "元"); } } public class WechatPaymentStrategy implements PaymentStrategy { @Override public void pay(double amount) { // 实现微信支付逻辑 System.out.println("使用微信支付:" + amount + "元"); } } ``` 3. 定义工厂接口 PaymentFactory,其中包含一个 createPayment 方法用来创建支付策略对象。 ```java public interface PaymentFactory { PaymentStrategy createPayment(); } ``` 4. 定义具体的支付工厂实现类,例如 AlipayPaymentFactory 和 WechatPaymentFactory,实现 PaymentFactory 接口中的 createPayment 方法。 ```java public class AlipayPaymentFactory implements PaymentFactory { @Override public PaymentStrategy createPayment() { return new AlipayPaymentStrategy(); } } public class WechatPaymentFactory implements PaymentFactory { @Override public PaymentStrategy createPayment() { return new WechatPaymentStrategy(); } } ``` 5. 定义支付模板类 PaymentTemplate,其中包含一个 pay 方法用来实现支付的公共流程,该方法调用 PaymentFactory 创建支付策略对象,并调用支付策略的 pay 方法实现支付功能。 ```java public abstract class PaymentTemplate { public void pay(double amount) { PaymentStrategy paymentStrategy = createPaymentStrategy(); paymentStrategy.pay(amount); } protected abstract PaymentStrategy createPaymentStrategy(); } ``` 6. 定义具体的支付模板类实现类,例如 AlipayPaymentTemplate 和 WechatPaymentTemplate,实现 PaymentTemplate 中的 createPaymentStrategy 方法,返回对应的支付策略对象。 ```java public class AlipayPaymentTemplate extends PaymentTemplate { @Override protected PaymentStrategy createPaymentStrategy() { return new AlipayPaymentFactory().createPayment(); } } public class WechatPaymentTemplate extends PaymentTemplate { @Override protected PaymentStrategy createPaymentStrategy() { return new WechatPaymentFactory().createPayment(); } } ``` 7. 在 SpringBoot 项目中使用支付模板类实现不同支付方式的接口,例如 PaymentController,其中包含一个 pay 方法用来接收支付请求,根据支付方式调用对应的支付模板类实现支付功能。 ```java @RestController public class PaymentController { @GetMapping("/pay") public String pay(@RequestParam("amount") double amount, @RequestParam("type") String type) { PaymentTemplate paymentTemplate = null; if ("alipay".equals(type)) { paymentTemplate = new AlipayPaymentTemplate(); } else if ("wechat".equals(type)) { paymentTemplate = new WechatPaymentTemplate(); } else { return "不支持的支付方式:" + type; } paymentTemplate.pay(amount); return "支付成功:" + amount + "元"; } } ``` 这样,我们就可以通过策略模式工厂模式和模板方法模式来实现不同支付方式的接口,使得代码更加灵活、可维护性更好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

埃泽漫笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值