文章目录
创建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);
}
校验装饰者模式是否正常工作
如下图(示例):
接口调用逻辑讲解
请求进来
如下图(示例):