设计模式之状态模式

本文介绍了如何运用状态模式来改善订单状态在业务流程中的处理,避免使用switch或if语句导致的代码复杂性和高耦合。通过定义抽象状态接口和具体状态实现类,实现了状态的切换和业务逻辑的分离,同时展示了如何在实际项目中结合SpringUtil获取bean进行状态切换操作,降低了代码的阅读难度和维护成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计模式之状态模式

小编已经很长时间没有来写文章,刚好最近在看设计模式。为了督促自己坚持学习下去,小编把今天认真学习状态模式,并结合在实际项目中的应用来说说心得体会。有不足或者需要纠正之处,欢迎读者留言指正,我会虚心学习
不多说了,直接切入正题
相信在项目中大家也都遇到过与订单相关的业务,在业务中订单状态的切换会直接或者间接引入第三方业务处理。有人可能使用了switch分支处理,导致整个类方法很大,或者引入的业务越来越复杂,致使代码耦合度很高;也有人可能使用了if语句判断,导致代码读取很不方便。那么今天小编结合在项目中的使用就介绍下23中设计模式之状态模式
在这里插入图片描述
这里我们引入一个一张结构图直观说明
状态模式包含以下主要角色。
环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

简单了解了之后 我们来使用设计模式-简单工厂模式定义接口并实现
1.定义接口 订单状态服务

/**
 * 使用状态模式控制  不同状态业务流转
 * @author lgl
 * @date 2021/8/31
 */
public interface OrderStateService {

    /**
     * 状态不同返回结果可能不同
     * @return
     */
    Object orderService();

    /**
     * 类标识
     * @return
     */
    String stateFlag();
}

2.定义切换签收-状态切换实现类

/**
 * 签收逻辑处理
 * 比如:签收后需要 结束订单  消息通知收货人和发货人
 * 可能还会涉及到触发资金结算问题
 * @author lgl
 * @date 2021/8/31
 */
@Slf4j
@Service
public class OrderSignedStateServiceImpl implements OrderStateService {
	
    @PostConstruct
    @Override
    public String stateFlag() {
        SpringUtil.STATE_MAP.put("signed","alreadySignedOrderStateServiceImpl");
        return "signed";
    }

    @Override
    public Object orderService() {
        log.info("状态已经切换到已签收");
        return "signed";
    }
}

3.定义发货-状态实现类

/**
 * 商家发货后
 * 如果用户开通了消息提醒功能  消息通知用户商家已发货以及货品定位信息
 * @author lgl
 * @date 2021/8/31
 */
@Slf4j
@Service
public class OrderShipStateServiceImpl implements OrderStateService {

    @PostConstruct
    @Override
    public String stateFlag() {
        SpringUtil.STATE_MAP.put("Shipped","shippedAlreadyOrderStateServiceImpl");
        return "Shipped";
    }
	/**
	
    @Override
    public Object orderService() {
        log.info("状态已经切换到配送中");
        return "shipped";
    }
}

这里小编就定义两个实现类吧,其中实现类这种 stateFlag() 需要项目启动加载,我使用适用了**@PostConstruct** 注解来解决启动后加载。当前读者也可以使用让实现类实现 InitializingBean类中接口afterPropertiesSet() 来替换小编的stateFlag() ,毕竟条条大路通罗马。

/**
 * @author lgl
 * @date 2021/8/31
 */
@Slf4j
@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext context;

    /**
     * 状态与类名的映射
     */
    public static Map<String,String> STATE_MAP = new HashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtil.context = applicationContext;
    }

    /**
     * 获取上下文对象
     * @return
     */
    public static ApplicationContext getContext(){
        return context;
    }

    /**
     * 根据name获取对象bean
     * @param name
     * @return
     */
    public static Object getBean(String name){
        return getContext().getBean(name);
    }

    /**
     * 根据class获取对象bean
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> clazz){
        return getContext().getBean(clazz);
    }

    /**
     * 根据name 以及对象指定返回bean
     * @param name
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(String name,Class<T> clazz){
        //改造前: name是之具体的类名
        //改造后:name为状态映射类名  这样前端直接传具体的状体就可以了  也可以把该参数维护成枚举 这样就省去了接口中的stateFlag()方法的的标记
        String clsName = STATE_MAP.get(name);
        return getContext().getBean(clsName,clazz);
    }
}

读者也可以使用hutool工具包中的SpringUtil来通过上下文获取bean实例对象,这里不做赘述
4.自定义环境上下文

/**
 * 方式一:
 * 通过注入到组件中调用状态流转事件
 * @author lgl
 * @date 2021/8/31
 */
public class StateContext {

    private OrderStateService orderStateService;

    public StateContext(OrderStateService orderStateService){
        this.orderStateService = orderStateService;
    }
    /**
     * 入参订单号
     * @param orderNo
     */
    public void switchState(String orderNo){
        orderStateService.orderService();
    }
}

5.通过postman调用接口

**
 *
 * 状态模式  其实类似于 switch 分支处理的做法
 * 在业务处理时  通过上下文直接获取bean对象  通过bean对象操作业务数据
 *
 * 原生状态模式需改造成符合当前业务
 * @author lgl
 * @date 2021/8/31
 */
@RestController
@RequestMapping("order")
public class OrderStateController {

    @GetMapping("state")
    public String orderState(String stateBeanId){
        // 通过spring上下文获取bean对象stateBeanId为类名称  也可以不做封装  直接使用 hutool 中的 SpringUtil
        OrderStateService state = SpringUtil.getBean(stateBeanId, OrderStateService.class);
        StateContext stateContext = new StateContext(state);
        stateContext.switchState(stateBeanId);
        return "OK";
    }
}

为了方便小编把逻辑代码卸载了控制层,实际项目中控制层制作转发调用业务层。这里不做具体的postman调用结果。读者可自行调试运行
在整个过程中,小编没有完全使用原生的设计模式,通过改造注入小编的部分思想。因为我一直认为:

读书百遍其义自见
接下来小编会把模板模式结合策略模式在支付领域的实际应用写一篇文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值