首页 > 其他分享 >【设计模式】策略模式在项目中的实战运用

【设计模式】策略模式在项目中的实战运用

时间:2023-11-05 19:35:31浏览次数:26  
标签:实战 confirmReq 处理 void 责任 BizJudgmentConfirmReq 运用 设计模式 public



目录

  • 前言思考
  • 实现落地
  • 小结


前言思考

随着业务需求不断迭代更新,系统逻辑越来越复杂。if else堆砌让人眼花缭乱。
那么此时就可以考虑使用设计模式,重构代码逻辑

采用什么设计模式,或者哪几种设计模式组合,与实际业务场景、逻辑有关系

以下面这个场景为例:

现在要将一批货物从A地点运往B地点,涉及三方:始发方、目的方、运输媒介方,货物如果在此时发生了丢失,那么具体是哪一方的责任?
现在承担包裹问题责任方有四种:始发方、目的方、始发方和目的方、运输媒介方
每种责任方处理结果,都有不同的处理方案,例如如果是运输丢失,那么司机的人力公司需要承担这部分赔偿,如果是始发地,则这部分物品成本需要挂在始发地等等

如果用if else 去写责任方处理结果的方法,那么就要嵌套好几层,如下伪代码所示:

if(jugmentParty == "始发方"){
	//始发方处理
}else if(jugmentParty == "目的方"){
	//目的方处理
}else if(jugmentParty == "始发方和目的方"){
	//始发方和目的方处理
}else{
	//运输媒介方处理
}

责任方会随着业务场景不断增加,可能还会增加快递员的责任,这么无限套下去,这个方法中的代码会长,并且不易扩展,每次都要动这个方法的东西,很难不保证其他正常运行的逻辑不受影响,非常不符合单一职责原则和开闭原则。

并且业务侧希望可以按照明细商品纬度处理责任或者整个运单包裹纬度处理责任,这有什么区别呢,例如说一个包裹里面有9个杯子,只有一个碎了,那实际上只需要赔偿一个杯子的价格即可,整单责任。例如包裹丢失等。

这种情况下,就可以抽象一下业务场景,无论有多少责任方,要做的事情都是包裹责任处理,处理分两种,一种是单个商品纬度处理,一种是整个包裹纬度处理。然后针对不同责任方,有不同的处理细节。

这种场景我觉得十分适合使用策略模式。

实现落地

(1)首先创建一个统一接口类,定义整包裹处理和单商品处理的方法

@Component("JudgmentStrategy")
public interface JudgmentStrategy {
    /**
     * 整包裹处理责任
     * @param confirmReq
     */
    void wholeOrderOperate(BizJudgmentConfirmReq confirmReq);

    /**
     * 单个商品处理责任
     * @param confirmReq
     */
    void singleOrderOperate(BizJudgmentConfirmReq confirmReq);
}

(2)创建不同责任方的实现类,实现此接口的两个方法

始发地

/**
 * 始发地责任处理
 */
@Slf4j
@Component("Origin")
public class OriginJudgmentStrategy implements JudgmentStrategy{
    @Override
    public void wholeOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地整单处理责任结果
    }

    @Override
    public void singleOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地单个商品处理责任结果
    }
}

目的地责任处理

/**
 * 目的地责任处理
 */
@Slf4j
@Component("Dest")
public class DestJudgmentStrategy implements JudgmentStrategy{
    @Override
    public void wholeOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地整单处理责任结果
    }

    @Override
    public void singleOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地单个商品处理责任结果
    }
}

始发地&目的地双方责任处理

/**
 * 始发地&目的地双方责任处理
 */
@Slf4j
@Component("OriginAndDest")
public class OriginAndDestJudgmentStrategy implements JudgmentStrategy{
    @Override
    public void wholeOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地整单处理责任结果
    }

    @Override
    public void singleOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地单个商品处理责任结果
    }
}

运输方责任处理

/**
 * 运输方责任处理
 */
@Slf4j
@Component("Transport")
public class TransportJudgmentStrategy implements JudgmentStrategy{
    @Override
    public void wholeOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地整单处理责任结果
    }

    @Override
    public void singleOrderOperate(BizJudgmentConfirmReq confirmReq) {
        //始发地单个商品处理责任结果
    }
}

(3)创建一个Context类,用于关联调用方和策略方法的一个媒介,也叫上下文。也就是说我们真正去调用策略方法是不直接引用JudgmentStrategy的,而且引用Context类。
上面通过工厂的形式创建策略类的实现类,直接通过@Autowired注入到Context上下文中。

@Slf4j
@Component
public class JudgmentStrategyContext {

    private final Map<String, JudgmentStrategy> strategyMap = new ConcurrentHashMap<String, JudgmentStrategy>();

    /**
     * 注入所有实现了JudgmentStrategy接口的Bean
     *
     * @param strategyMap
     */
    @Autowired
    public void JudgmentStrategy(Map<String, JudgmentStrategy> strategyMap) {
        this.strategyMap.clear();
        strategyMap.forEach(this.strategyMap::put);
    }

    /**
     * 整单处理库存
     *
     * @param confirmReq
     */
    public void wholeOrderOperate(BizJudgmentConfirmReq confirmReq) {
        log.info("JudgmentStrategyContext#wholeOrderOperate--入参confirmReq:{}", JSONObject.toJSONString(confirmReq));      	
        strategyMap.get(getBean(confirmReq)).wholeOrderOperate(confirmReq);
    }

     /**
     * 明细纬度处理库存
     *
     * @param confirmReq
     */
    public void singleOrderOperate(BizJudgmentConfirmReq confirmReq) {
        log.info("JudgmentStrategyContext#singleOrderOperate--入参confirmReq:{}", JSONObject.toJSONString(confirmReq));
        strategyMap.get(getBean(confirmReq)).singleOrderOperate(confirmReq);
    }

    private String getBean(BizJudgmentConfirmReq confirmReq) {
	    if(confirmReq == null || confirmReq.getJudgmentParty() == null){
	    	throw new BusinessException("责任处理失败,责任方入参不能空");
	    }
        HandoverJudgmentPartyEnum partyEnum = HandoverJudgmentPartyEnum.getEnumByValue(confirmReq.getJudgmentParty());
        if (partyEnum == null) {
            throw new BusinessException("责任处理失败,未匹配到处理责任方");
        }
        switch (partyEnum) {
        	case TRANSPORT:
                return "Transport";
            case ORIGIN:
                return "Origin";
            case DEST:
                return "Dest";
            case ORIGIN_AND_DEST:
                return "OriginAndDest";
            default:
                throw new BusinessException("责任处理失败,未匹配到处理责任方");
        }
    }
}

补充枚举类以及入参类

/**
 * 责任方枚举
 */
public enum HandoverJudgmentPartyEnum {
    TRANSPORT(1, "运输媒介方"),
    ORIGIN(2, "始发方"),
    DEST(3, "目的方"),
    ORIGIN_AND_DEST(4, "始发方&目的方"),
    ;

    private Integer value;
    private String name;

    HandoverJudgmentPartyEnum(Integer value, String name) {
        this.value = value;
        this.name = name;
    }

    public Integer getValue() {
        return value;
    }

    public String getName() {
        return name;
    }

    public static String getNameByValue(Integer value){
        for(HandoverJudgmentPartyEnum sourceEnum: HandoverJudgmentPartyEnum.values()){
            if(sourceEnum.getValue().equals(value)){
                return sourceEnum.getName();
            }
        }
        return null;
    }

    public static HandoverJudgmentPartyEnum getEnumByValue(Integer value) {
        if (null == value) {
            return null;
        }
        for (HandoverJudgmentPartyEnum item : HandoverJudgmentPartyEnum.values()) {
            if (Objects.equals(value,item.value)) {
                return item;
            }
        }
        return null;
    }
}
/**
 * 责任方确认入参
 */
@Data
public class BizJudgmentConfirmReq {
    /**
     * 单号编码
     */
    private String businessCode;

    /**
     * 责任方 {@linkplain com.jd.hr.domain.enums.HandoverJudgmentPartyEnum}
     */
    private Integer judgmentParty;

    /**
     * 责任依据
     */
    private String judgmentBasis;

    /**
     * 操作人erp
     */
    private String operateUser;

    /**
     * 操作人姓名
     */
    private String operateName;
}

(4)调用策略方法

@Slf4j
@Service
public class JugmentOrderServiceImpl extends IJugmentOrderService{
	@Resource
    private JudgmentStrategyContext judgmentStrategyContext;
    
	@Override
    public void wholeOrderOperateTest(BizJudgmentConfirmReq confirmReq) {
        judgmentStrategyContext.wholeOrderOperate(confirmReq);
    }
    @Override
    public void singleOrderOperateTest(BizJudgmentConfirmReq confirmReq) {
        judgmentStrategyContext.singleOrderOperate(confirmReq);
    }
}

小结

通过上面的代码实现,可以看出接口类只负责业务策略的定义,定义各个方面策略的标准;策略的具体实现,可以认为是多个方面的策略,或者是多个角色的策略就有不同的实现。

Context上下文类负责业务逻辑的编排,封装了策略的执行细节,具体的实现服务只需要调用Context类的方法,而不需要了解具体策略对象的实现细节。如何编排策略完全在Context封装好。

策略模式的优势:
通过策略模式(或变种)的应用,实现了面向接口而非实现编程,满足了职责单一、开闭原则,从而达到了功能上的高内聚低耦合、提高了可维护性、扩展性以及代码的可读性。

设计模式是为了帮助我们从复杂的业务场景中解脱出来,提升代码的可读性,可维护性。但是在实际应用过程中也不必拘泥于设计模式本身,也可以结合所使用的框架进行变种处理。


标签:实战,confirmReq,处理,void,责任,BizJudgmentConfirmReq,运用,设计模式,public
From: https://blog.51cto.com/u_15301254/8194773

相关文章

  • java IO设计模式:观察者模式
    NIO中的文件目录监听服务使用到了观察者模式。NIO中的文件目录监听服务基于WatchService接口和Watchable接口。WatchService属于观察者,Watchable属于被观察者。Watchable接口定义了一个用于将对象注册到WatchService(监控服务)并绑定监听事件的方法register。WatchServ......
  • 云原生架构实战06 Kubernetes的核心概念
    一、有状态和无状态二、对象规约和状态spec是规约规格的意思,描述了对象的期望状态--希望对象所具有的特征,当创建Kubernetes对象是,必须提供兑现对象的规约,用来描述该对象的期望状态,以及关于对象的一些基本信息(名称)状态status:表示对象的实际状态,该属性由k8s自己维护,会通过一系列......
  • 设计模式-单例械
    //Seehttps://aka.ms/new-console-templateformoreinformation//设计模式-单例模式//目的:唯一性,内存资源,GCtffu//保证整个系统中一个类只有一个对象的实例usingSystem.Threading.Channels;Singleton.GetInstance().GetGuid();Singleton.GetInstance().GetGuid()......
  • 设计模式-策略模式
    策略模式:定义一系列的算法,将每个算法分别封装起来,让它们可以互相替换。策略模式用于算法的自由切换和扩展,它是使用较为广泛的设计模式之一。策略模式对应于解决某一问题的一个算法族,允许用户从该算法中任选一个算法解决某一问题,同时可以方便地更换算法或者增加新算法。策略模式......
  • 深度解析BERT:从理论到Pytorch实战
    本文从BERT的基本概念和架构开始,详细讲解了其预训练和微调机制,并通过Python和PyTorch代码示例展示了如何在实际应用中使用这一模型。我们探讨了BERT的核心特点,包括其强大的注意力机制和与其他Transformer架构的差异。关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架......
  • java——redis随笔——实战——分布式缓存——哨兵
                                                                           ......
  • 设计模式—结构型模式之适配器模式
    设计模式—结构型模式之适配器模式将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,适配器模式分为类结构型模式(继承)和对象结构型模式(组合)两种,前者(继承)类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少......
  • Stream实战用例1
    Java8Stream代码少,功能强大,实乃效率利器。这里我列举自己常用的Stream使用示例。一.流式赋值1.从一个List转到另一个List参考objectList=objectList.stream().map(object->{ObjectobjectNew=newObject();BeanUtils.copyProperties(......
  • java——redis随笔——实战——分布式缓存——主从
                                                                               ......
  • 设计模式
    一、工厂模式1、简单工厂模式通过一个具体的工厂类,根据传入不同的参数,生成实际对象2、工厂方法模式在工厂方法模式中,不再由单一的工厂类生产产品,而是由工厂类的子类实现具体的产品创建。当增加一个产品时,只需增加一个相应的工厂类的子类,实现生产这种产品,从而解决简单工厂生产......