13

真实项目案例实战—【状态设计模式】使用场景

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzU2NDc4MjE2Ng%3D%3D&%3Bmid=2247484461&%3Bidx=1&%3Bsn=eca9b30d7ecd25ba72bf61177b0a0d8c
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

ym2emyE.jpg!web

写在前面:设计模式源于生活,而又高于生活!

什么是状态模式

状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。

状态模式应用场景

1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。

2.操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。 通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。

这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

状态模式实现

需要重构的代码

public class OrderService {


    public String orderState(String state) {
        if (state.equals("0")) {
            return "已经发货";
        }
        if (state.equals("1")) {
            return "正在运送中...";
        }
        if (state.equals("2")) {
            return "正在派送中...";
        }
        if (state.equals("3")) {
            return "已经签收";
        }
        if (state.equals("4")) {
            return "拒绝签收";
        }
        if (state.equals("5")) {
            return "订单交易失败";
        }
        return "未找到对应的状态";
    }
}

状态模式与策略模式区别

策略模式结构图:

u2MV7r3.png!web

状态模式结构图

qmMZ3mQ.png!web

1、状态模式重点在各状态之间的切换从而做不同的事情,而策略模式更侧重于根据具体情况选择策略,并不涉及切换。

2、状态模式不同状态下做的事情不同,而策略模式做的都是同一件事,例如聚合支付平台,有支付宝、微信支付、银联支付,虽然策略不同,但最终做的事情都是支付,也就是说他们之间是可替换的。反观状态模式,各个状态的同一方法做的是不同的事,不能互相替换。

状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。

在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。

状态模式实现

OrderState 定义统一抽象接口

public interface OrderState {

    /**
     * 返回都会不一样
     *
     * @return
     */
    public Object orderService();

}

OrderState 实现类:AlreadySignedOrderState

@Slf4j
@Component
public class AlreadySignedOrderState implements OrderState {
    @Override
    public Object orderService() {
        log.info(">> 切换已经签收状态");
        return "切换已经签收状态";
    }
}

OrderState 实现类:InTransitOrderState

@Slf4j
@Component
public class InTransitOrderState implements OrderState {
    @Override
    public String orderService() {
        log.info(">>>切换为正在运送状态...");
        return "success";
    }
}

OrderState 实现类:ShippedAlreadyOrderState

@Slf4j
@Component
public class ShippedAlreadyOrderState implements OrderState {
    public String orderService() {
        log.info(">>>切换为已经发货状态..");
        return "已经发货..";
    }
}

Context上下文:StateContext 

public class StateContext {
    private OrderState orderState;

    public StateContext(OrderState orderState) {
        this.orderState = orderState;
    }

    public void switchStateOrder() {
        orderState.orderService();
    }
}

OrderController 

@RestController
public class OrderController {

    @RequestMapping("/order")
    public String order(String stateBeanId) {

        //1.使用Spring上下文获取bean中对象
        OrderState orderState = SpringUtils.getBean(stateBeanId, OrderState.class);
        // 2.使用上下文切换到不同的状态
        StateContext stateContext = new StateContext(orderState);
        stateContext.switchStateOrder();

        // 如果写多重if判断的话 整个代码流程 耗时比较长   直接Spring中精准定位到策略或者是状态的话 Map get方法的时候底层是数组
        return "success";
    }
}

SpringUtils 

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

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

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }

}

pom依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>
    <dependencies>
        <!-- sprinboot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

启动类

@SpringBootApplication
public class AppOrderState {
    public static void main(String[] args) {
        SpringApplication.run(AppOrderState.class);
    }
}

测试结果

访问:http://127.0.0.1:8080/order?stateBeanId=alreadySignedOrderState

控制台输出:>> 切换已经签收状态

访问:http://127.0.0.1:8080/order?stateBeanId=inTransitOrderState

控制台输出:>>>切换为正在运送状态...

访问:http://127.0.0.1:8080/order?stateBeanId=shippedAlreadyOrderState

控制台输出:>>>切换为已经发货状态..

RjmAzuu.gif

基本数据类型使用姿势不对导致的线上"死循环"问题排查

百度网盘"不限速"工具 Pandownload开发者被抓

分布式中采用Logback的MDC机制与AOP切面结合串联日志

三个方案解决Elasticsearch深度翻页问题

彻底搞清分库分表(垂直分库,垂直分表,水平分库,水平分表)

小白也能学会的RAID磁盘冗余阵列教程

IraEBbe.jpg!web

欢迎分享转发,有帮助的话点个“在看”


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK