【设计模式】【第三章】【平台积分红包发放场景】【装饰者模式】

创建design-demo项目

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

本文基于【设计模式】【第一章】【支付场景】【策略模式 + 工厂模式 + 门面模式 + 单例模式】进行改造

需求分析

在这里插入图片描述
如果是传统的开发模式进行开发,可能也就在支付完成之后写平台币和红包发放的业务代码,这里就可能影响支付业务逻辑,所以我们需要在不动用业务层代码的情况下,再支付后添加一个功能,这里就需要使用装饰者模式。

改动StrategyFacade

代码如下(示例):

package com.example.designdemo.pay.facade;

import com.example.designdemo.pay.additionalDecorator.AddFuncDecorator;
import com.example.designdemo.pay.context.PayContext;
import com.example.designdemo.pay.factory.AddFuncFactory;
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 {

    // 定义一个map,将对应关系提前初始化好。
    // 双十一的时候,有大量的用户进行下单(千万级),就会造成千万级的pay接口的调用。
    // 很可惜,这部分代码里边有两个 new 关键字(new PayContext(payStrategy) 和 new AddFuncDecorator)。
    // 如果瞬时见。有几十万的并发进来,那么会创建几十万个 context对象和 addFunc对象,造成 年轻代的eden区的频繁对象创建
    // 虽然说调用完就进行了对象的垃圾收集,但是这么多的访问对象进来会造成,minorgc。
    // 1. 单例模式吗?PayContext创建是基于payStrategy,不止一种paycontext啊,用单例不行呀。 AddFuncDecorator 是基于PayContext
    // 创建的,PayContext 不止一种,AddFuncDecorator 也不止一种。
    // 2. 享元模式。享元模式是单例模式的一种思想升级。单例模式,针对的是同一种对象,没有任何不同的细节。而享元模式,针对多个对象。
    // 多个对象:同一种class,但是里边的属性有些许不同。PayContext是同一种对象吧?是的; PayContext 是不是有细节上的不同呢?是的,
    // payStrategy不同; 那么我们是否可以知道这个PayContext的种类数量呢?是的,目前有三种。 享元模式能够对这可控数量的有不同细节的
    //同一种class对象进行共享,保证我们的程序不频繁的创建对象。
    public static Boolean pay(PayBody payBody) {
        //获取我们的 策略枚举
        StrategyEnum strategyEnum = getStrategyEnum(payBody.getType());
        if(strategyEnum == null) {
            return false;
        }
        //获取我们的策略对象
        PayStrategy payStrategy = StrategyFactory.getPayStrategy(strategyEnum);
        //生成我们的策略上下文
        PayContext context = new PayContext(payStrategy); // TO DO
        // 装饰一下 context,。立马多了一个功能
        // 我看这行代码啊,就不顺眼。代理模式搞他。
        AddFuncDecorator addFuncDecorator = (AddFuncDecorator) AddFuncFactory.getAddFunc(context);
        //进行扣款
        return addFuncDecorator.execute(payBody);
    }

    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;
        }
    }

}

创建AddFuncFactory

代码如下(示例):

package com.example.designdemo.pay.factory;

import com.example.designdemo.pay.additionalDecorator.AbstractAddFuncDecorator;
import com.example.designdemo.pay.additionalDecorator.AddFuncDecorator;
import com.example.designdemo.pay.context.PayContext;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: zhiwei Liao
 * @Date: 2022/9/25 20:53
 * @Description:
 */
public class AddFuncFactory {
    // 工厂的目的是生产 AddFuncDecorator; 生产几个啊? 多个:享元
    // key 应该是能够和 AbstractAddFuncDecorator 做成对应的东西。
    // 这个map最多保存是三个对象。
    public final static Map<PayContext, AbstractAddFuncDecorator> maps = new ConcurrentHashMap<>();

    public static AbstractAddFuncDecorator getAddFunc(PayContext payContext) {
        if(maps.get(payContext) == null) {
            AddFuncDecorator addFuncDecorator = new AddFuncDecorator(payContext);
            maps.put(payContext, addFuncDecorator);
        }
        return maps.get(payContext);
    }
}

改动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 20:53
 * @Description:动态地给一个对象添加一些额外的职责. 就得在根儿上添加。PayContext 就是我们的被装饰者,因为我们想给payContext添加额外功能:平台币更新和红包.所以我们选择使用装饰者模式。被装饰者必须要有 接口或者抽象类。
 */
public class PayContext extends AbstractPayContext{
    private PayStrategy payStrategy;

    public PayContext(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }

    @Override
    public Boolean execute(PayBody payBody) {
        return this.payStrategy.pay(payBody);
    }
}

创建AbstractPayContext

代码如下(示例):

package com.example.designdemo.pay.context;


import com.example.designdemo.pay.pojo.PayBody;
/**
 * @Author: zhiwei Liao
 * @Date: 2022/9/25 20:53
 * @Description:
 */
public abstract class AbstractPayContext {
    public abstract Boolean execute(PayBody payBody);
}

创建AddFuncDecorator

代码如下(示例):

package com.example.designdemo.pay.additionalDecorator;

import com.example.designdemo.pay.context.AbstractPayContext;
import com.example.designdemo.pay.pojo.PayBody;

/**
 * @Author: zhiwei Liao
 * @Date: 2022/9/25 20:53
 * @Description:abstractPayContext 不是共享的,因为有的小伙伴选择 zfb 支付,有的小伙伴选择wx支付,等等。。。
 */
public class AddFuncDecorator extends AbstractAddFuncDecorator{
    public AddFuncDecorator(AbstractPayContext abstractPayContext) {
        super(abstractPayContext);
    }

    // 新活儿
    @Override
    public void additionalFunction(PayBody payBody) { // 共享的,跟支付策略没有任何关系
        String product = payBody.getProduct();
        // 从db里边获取 product的详细信息。
        // 从配置中心(redis缓存)里获取产品的更新策略。
        // 根据策略更新用户平台币 或(和) 发放红包。
        System.out.println("更新平台币成功,发送红包到用户优惠券模块成功。");
    }

    @Override
    public Boolean execute(PayBody payBody) { // 算共享的。共享的调用逻辑
        Boolean result = super.execute(payBody); //老活儿
        this.additionalFunction(payBody); // 新活儿. 新活儿的各种重试,失败补偿
        return result;
    }

}

创建AbstractAddFuncDecorator

代码如下(示例):

package com.example.designdemo.pay.additionalDecorator;


import com.example.designdemo.pay.context.AbstractPayContext;
import com.example.designdemo.pay.pojo.PayBody;
/**
 * @Author: zhiwei Liao
 * @Date: 2022/9/25 20:53
 * @Description:
 */
public abstract class AbstractAddFuncDecorator extends AbstractPayContext {
    // 这是我们的装饰器类。专门干装修的。 专门添加新功能的(平台币,红包)
    // 装饰的是谁啊? 我作为一个称职的装饰器,我必须得知道装饰的是谁,不然我咋干活儿啊。
    private AbstractPayContext abstractPayContext = null;

    public AbstractAddFuncDecorator(AbstractPayContext abstractPayContext) {
        this.abstractPayContext = abstractPayContext;
    }

    // 开始干活儿
    //1. 老活儿。 支付。但是我又不能修改支付代码,也不能修改支付逻辑。
    @Override
    public Boolean execute(PayBody payBody) {
        return abstractPayContext.execute(payBody);
    }

    //2. 老活儿不合适,没你装饰器照样能execute。 新活儿:平台币,红包)
    public abstract void additionalFunction(PayBody payBody);
}

校验装饰者模式是否正常工作

如下图(示例):
在这里插入图片描述在这里插入图片描述

接口调用逻辑讲解

请求进来
如下图(示例):
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Java程序员廖志伟

赏我包辣条呗

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

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

打赏作者

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

抵扣说明:

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

余额充值