当前位置:   article > 正文

互联网架构-精讲设计模式-008:外观(门面)与状态模式_外观模式和状态模式区别

外观模式和状态模式区别

1 为什么需要使用外观模式

课程内容:
1、什么是外观模式?外观模式应用场景
2、外观模式的类图与代码实现
3、什么是状态模式?状态模式应用场景
4、状态模式与策略模式的区别

什么是外观模式
外观模式(Facade),隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。

外观模式应用场景
在这里插入图片描述
简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中,涉及到3个角色:
1.门面角色:外观模式的核心。它被客户角色调用,它熟悉子系统的功能;内部根据客户角色的需求预定了几种功能的组合。
2.子系统角色:实现了子系统的功能。它内部可以有系统内的相互交互,也可以有供外界调用的接口。
3.客户角色:通过调用Facede来完成要实现的功能。

需要重构代码

@Slf4j
public class PayCallbackService {
    // 用户下单成功后,有那些操作?
    // 1.增加支付回调接口日志
    // 2.修改订单数据库状态为已经成功
    // 3.调用积分服务接口
    // 4.调用消息服务平台服务接口

    public boolean callback(Map<String, String> verifySignature) {
        // 1.第一步打印日志信息
        String orderId = verifySignature.get("orderId"); // 获取后台通知的数据,其他字段也可用类似方式获取
        String respCode = verifySignature.get("respCode");
        log.info("orderId:{},respCode:{}", orderId, respCode);
        // 2.修改订单状态为已经支付
        new PaymentTransactionMapper() {
            @Override
            public void updatePaymentStatus() {
                log.info(">>>修改订单状态为已经支付>>>>>");
            }
        }.updatePaymentStatus();
        // 3.调用积分接口增加积分
        HttpClientUtils.doPost("jifen.com", "积分接口");
        // 4.调用消息服务平台提示
        HttpClientUtils.doPost("msg.com", "调用消息接口");
        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
public interface PaymentTransactionMapper {
    void updatePaymentStatus();
}
  • 1
  • 2
  • 3
@Slf4j
public class HttpClientUtils {

    public static String doPost(String url, String text) {
        log.info(">>>Url:{},text:{}", url, text);
        return "success";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以采用外观(门面/包装)模式,使用一个接口封装复杂的业务逻辑流程,让客户端使用起来更加简单。

2 使用外观模式重构复杂业务逻辑代码

在这里插入图片描述
子服务类

@Service
public class LogService {

    public void logService(){
        System.out.println(">>>第一个模块:日志的收集与打印..");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
@Slf4j
public class PaymentService {

    public void updatePaymentStatus(){
        new PaymentTransactionMapper() {
            @Override
            public void updatePaymentStatus() {
                log.info(">>>第二个模块:修改订单状态为已经支付..");
            }
        }.updatePaymentStatus();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
@Service
public class IntegralService {

    public void addIntegral(){
        HttpClientUtils.doPost("jifen.com", "积分接口");
        System.out.println(">>>第三个模块:调用增加积分模块..");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
@Service
public class MsgService {
    public void sendMsg() {
        HttpClientUtils.doPost("msg.com", "调用消息接口");
        System.out.println(">>>第四个模块:调用消息服务平台模块..");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

门面类

@Component
public class PayFacade {
    @Autowired
    private LogService logService;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private IntegralService integralService;
    @Autowired
    private MsgService msgService;

    public void facadeCallback() {

        // 1.第一步:日志收集
        logService.logService();
        // 2.第二部:修改订单状态
        paymentService.updatePaymentStatus();
        // 3.第三步:调用积分服务接口
        integralService.addIntegral();
        // 4.第四步:调用消息服务平台
        msgService.sendMsg();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

控制层

@RestController
public class PayController {

    @Autowired
    private PayCallbackService payCallbackService;

    @RequestMapping("/payCallback")
    public String payCallback() {
        payCallbackService.callback();
        return "success";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

启动类

@SpringBootApplication
public class AppFacade {
    public static void main(String[] args) {
        SpringApplication.run(AppFacade.class);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

运行结果:
在这里插入图片描述

3 总结外观模式的优缺点

优点
1.松散耦合:使得客户端和子系统之间解耦,让子系统内部的模块功能更容易扩展和维护;
2.简单易用:客户端根本不需要知道子系统内部的实现,或者根本不需要知道子系统内部的构成,它只需要跟Facade类交互即可。
3.更好的划分访问层次:有些方法是对系统外的,有些方法是系统内部相互交互的使用的。子系统把那些暴露给外部的功能集中到门面中,这样就可以实现客户端的使用,很好的隐藏了子系统内部的细节。
缺点:业务逻辑类很多程序变复杂

4 状态模式与策略模式的区别

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

状态模式应用场景
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

需要重构的代码

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 "未找到对应的状态";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

状态模式与策略模式区别
1、状态模式重点在各状态之间的切换从而做不同的事情,而策略模式更侧重于根据具体情况选择策略,并不涉及切换。
2、状态模式不同状态下做的事情不同,而策略模式做的都是同一件事,例如聚合支付平台,有支付宝、微信支付、银联支付,虽然策略不同,但最终做的事情都是支付,也就是说他们之间是可替换的。反观状态模式,各个状态的同一方法做的是不同的事,不能互相替换。
状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。
在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。

eg:整合排序算法、快速排序、选择排序、冒泡排序用什么模式? 策略模式,都是解决排序相关的问题;
和状态变化相关用状态模式,订单、交易、支付状态。

5 使用状态模式解决多重if判断

在这里插入图片描述
公共接口

public interface OrderState {

    /**
     * 每个状态都对应不同的返回
     * @return
     */
    public Object orderService();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

实现类

@Slf4j
@Component
public class AlreadySignedOrderState implements OrderState {
    @Override
    public Object orderService() {
        log.info(">> 切换为已签收状态..");
        return "已签收";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
@Slf4j
@Component
public class InTransitOrderState implements OrderState {

    @Override
    public Object orderService() {
        log.info(">> 切换为正在运送状态..");
        return "正在运送";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
@Slf4j
@Component
public class ShippedAlreadyOrderState implements OrderState {
    @Override
    public Object orderService() {
        log.info(">> 切换为已发货状态..");
        return "已发货";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

状态上下文

public class StateContext {

    private OrderState orderState;

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

    public String switchStateOrder() {
        Object o = orderState.orderService();
        return o.toString();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

控制层

@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);
        String result = stateContext.switchStateOrder();
        return result;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

启动类

@SpringBootApplication
public class AppState {
    public static void main(String[] args) {
        SpringApplication.run(AppState.class);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

运行结果:
在这里插入图片描述
写多重if判断,整个代码流程耗时比较长;直接Spring中精准定位到策略或者状态,底层通过Map集合封装,调用get方法的时候底层是数组,查询效率高。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/378144
推荐阅读
相关标签
  

闽ICP备14008679号