我开发中常用的四个设计模式

举个栗子

我任职于一家小电商,我这边的下单接口有如下的业务流程:

在这里插入图片描述

光看这流程图,就可以感知复杂。我在重构时就利用了设计模式,加强了它的扩展性、可读性。

模版方法

例如优惠券校验这个一小部分,伪代码如下:

if 是否使用优惠券 then 
优惠券校验
else if 
//do nothing
endif 

我第一个想到的就是模版方法。

将不变的部分放在父类,由不同的子类去实现变化的部分。

这里变的部分是校验逻辑,不变的是if-else。

父类 AbstractOrderSubmitTransactionTemplate 如下:

public abstract class AbstractOrderSubmitTransactionTemplate implements OrderSubmitTransactionTemplate{
		protected abstract boolean test(Context context);
        protected abstract void doValidate(Context context);
        protected abstract void doPrepare(Context context);
        protected abstract void doCommit(Context context);
        protected abstract void doRollback(Context context);

        @Override
        public void validate(Context context) {
            if(test(context)){
                //日志记录
                doValidate(context);
                //日志记录
            }
        }

        @Override
        public final void prepare(Context context) {
            if(test(context)){
                //日志记录
                doPrepare(context);
                //日志记录
            }
        }

        @Override
        public final void commit(Context context) {
            if(test(context)){
                //日志记录
                doCommit(context);
                //日志记录
            }
        }

        @Override
        public final void rollback(Context context) {
            if(test(context)){
                //日志记录
                doRollback(context);
                //日志记录
            }
        }
    }

根据接口分离原则,定义供调用者调用的接口OrderSubmitTransactionTemplate

 public interface  OrderSubmitTransactionTemplate{
		 void validate(Context context);
         void prepare(Context context);
         void commit(Context context);
         void rollback(Context context);
}

举例,用于处理优惠券的子类CouponTransactionTemplate实现:

public class CouponTransactionTemplate extends AbstractOrderSubmitTransactionTemplate{

        @Override
        public boolean test(Context context) {
            return context.isUseCoupon();
        }

        @Override
        protected void doValidate(Context context) {
            //优惠券校验
        }

        @Override
        protected void doPrepare(Context context) {
            //优惠券预扣减
        }

        @Override
        protected void doCommit(Context context) {
            //优惠券扣减提交
        }

        @Override
        protected void doRollback(Context context) {
            //优惠券扣减回滚
        }
    }

基于模版方法的改造就完成了,我的业务代码也就变成了下面这样:

public void submit(Context context){
            //校验
            stockTransactionTemplate.validate(context);
            couponTransactionTemplate.validate(context);
            activityTransactionTemplate.validate(context);
            //预扣减
            stockTransactionTemplate.prepare(context);
            couponTransactionTemplate.prepare(context);
            activityTransactionTemplate.prepare(context);
            try{
                //下单流程
                //确认扣减
                stockTransactionTemplate.commit(context);
                couponTransactionTemplate.commit(context);
                activityTransactionTemplate.commit(context);
            }catch (Exception e){
                //回滚扣减
                stockTransactionTemplate.rollback(context);
                couponTransactionTemplate.rollback(context);
                activityTransactionTemplate.rollback(context);
            }
}

责任链模式

光使用模版方法改造,其实还不够,只是减少了if-else,并没有符合开闭原则,也就是说当我需要加入一种全新的优惠券时,又需要改动我下单方法(submit)

所以,我又想到了责任链模式。

调用者将请求传给责任链,具体哪些个对象负责执行,由责任链上的对象自行判断是否处理。

我在AbstractOrderSubmitTransactionTemplate类中定义的test方法,其实已经可以实现对象自行判断是否处理。所以这里我只要把所有的AbstractOrderSubmitTransactionTemplate子类挨个轮询就可以实现责任链模式。

例如校验方法(validate)可以这样实现:

@Autowired
private List<AbstractOrderSubmitTransactionTemplate> transactionTemplates;
public void validate(Context context){
            for (AbstractOrderSubmitTransactionTemplate transactionTemplate : transactionTemplates) {
                transactionTemplate.validate(context);
            }
        }

这里可以利用spring的@Autowired注解,将AbstractOrderSubmitTransactionTemplate的子类注入到一个list中。

经过改造后,我的业务代码成了这样:

		public void submit(Context context){
            //校验
            validate(context);
            //预扣减
            prepare(context);
            try{
                //下单流程
                //确认扣减
                commit(context);
            }catch (Exception e){
                //回滚扣减
                rollback(context);
            }
        }

策略模式

假设某一天,随着公司业务扩张,需要根据不同的订单类型,执行不同的下单逻辑。也就是我的下单流程要改,有些订单类型插入A库,有些订单类型插入B库,有些订单类型可能不插库直接放到其他系统去。

伪代码如下

//校验
//预扣减
//下单流程
if 订单类型为1 then
插入Aelse if 订单类型为2 then
插入Belse if 订单类型为3 then
调用C系统同步订单
end if
//扣减提交/扣减回滚

校验、预扣减、扣减提交/扣减回滚这块和下单流程这块是一对多的关系,所以我这边想到的是利用策略模式去实现这个需求。

业务模块之间是1对多的关系,将每个模块封装成策略,组合使用。

下单流程策略接口OrderSubmitStrategy:

    public  interface OrderSubmitStrategy{
        void submit(Context context);
    }

依旧使用模版方法定义了抽象的父类

public  abstract class AbstractOrderSubmitStrategy implements OrderSubmitStrategy {
        protected abstract  void doSubmit(Context context);
        public final void submit(Context context){
            //日志记录
            this.doSubmit(context);
            //日志记录
        }
    }

其中一个子类如下:

public class OrderSubmitV1Strategy extends AbstractOrderSubmitStrategy{

        @Override
        protected void doSubmit(Context context) {
            //v1 下单
        }
    }

经过改造,我的业务代码变成了这样:

       public void submit(Context context,OrderSubmitStrategy orderSubmitStrategy){
            //校验
            validate(context);
            //预扣减
            prepare(context);
            try{
                //下单流程
                orderSubmitStrategy.submit(context);
                //确认扣减
                commit(context);
            }catch (Exception e){
                //回滚扣减
                rollback(context);
            }
        }

在具体调用时,根据不同策略执行不同的下单逻辑:

@PostMapping("/v1/submit")
    public SubmitRes submit(SubmitForm form){
        Context context = new Context(form);
        orderSubmitBean.submit(context,orderSubmitV1Strategy);
        return context.getSubmitRes();
    }

    @PostMapping("/v2/submit")
    public SubmitRes submit(SubmitForm form){
        Context context = new Context(form);
        orderSubmitBean.submit(context,orderSubmitV2Strategy);
        return context.getSubmitRes();
    }

观察者模式

下单之后,需要通知其他系统,比如大数据系统。这些通知并不需要保证强一致性,只需要最终一致性,一般我们都利用消息中间件来通知,但是通知多了,发送消息代码的严重影响代码简洁,而且每次有新的消息需要发送都需要改动submit方法。

于是,我就想到的观察者模式来实现。

当一个对象被修改时,则会自动通知依赖它的对象

观察者接口:

 public static interface OrderSubmitListener{
        void handle(Context context);
 }

notifyListeners方法:

@Autowired
private List<OrderSubmitListener> listeners;

        void notifyListeners(Context context){
            for (OrderSubmitListener listener : listeners) {
                listener.handle(context);
            }

        }

这里可以利用spring的@Autowired注解,将OrderSubmitListener的子类注入到一个list中。

改造后代码如下:

public void submit(Context context,OrderSubmitStrategy orderSubmitStrategy){
            //校验
            validate(context);
            //预扣减
            prepare(context);
            try{
                //下单流程
                orderSubmitStrategy.submit(context);
                //确认扣减
                commit(context);
            }catch (Exception e){
                //回滚扣减
                rollback(context);
            }
            notifyListeners(context);
        }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值