3
头图

1. 责任链模式

1.1. 定义

为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

1.2. 责任链的使用

1.2.1. 包含的角色

1. 抽象处理者(Handler)角色
image.png
2. 具体处理者(Concrete Handler)角色
image.png
image.png
3. 客户类(Client)角色
image.png
 以上代码通过职责链完成对用户参与抽奖过程中的地区和存量校验,只有通过这两个校验才能完成抽奖。

1.3. 责任链的优点

  1.  增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
  2. 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
  3. 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则.

1.4. 责任链的缺点

1. 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

2.  策略模式

2.1. 定义

定义一系列可互相替换的算法,并且每个算法独立封装,然后在运行的时候动态替换。策略模式的核心:一个抽象+多个具体的实现,策略持有类要持有实现类的集合(要用抽象类替代),程序调用时根据类型去策略持有类中找到对应的实现类,然后调用实现类的具体方法。

2.2. 策略模式的使用

2.2.1. 包含的角色

  1. 策略接口(抽象类)
  2. 具体策略的实现类
  3. 策略持有者类:持有所有策略,以触发执行。

2.2.2. 使用

存在多种实现方式,最简单采用Map,存储所有实现类;另一个利用Spring IOC AOP等功能优雅实现;案例:有阿里支付和微信支付等多种支付方式,每种支付方式有自己的支付逻辑,通过制定某种支付方式,来完成支付,可以采用策略模式。
1. 策略接口:
image.png
2. 具体的策略实现类:
image.png

image.png
3. 策略持有类:利用Spring的@Bean注解自动注入参数,将PayStrategy实现类注入,并将PayStrategyRunner(策略执行的类)注入容器。
image.png
 
image.png
 使用:
image.png
 标注类为哪个策略的注解
image.png
 参考文章

2.3. 策略模式优点

1. 添加策略时很方便,只添加一个策略的实现类即可,符合开闭原则(对新增开放,对修改关闭

  1. 逻辑解耦。每个策略负责自己的事情,调用方去选择使用哪个策略。符合单一职责原则。
  2. 提高了代码优雅度。调用方减少了对业务的if else的判断,直接给策略传入相应的类型即可。

2.4. 策略模式缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
  2. 由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观
             

    3. 适配器模式

3.1. 定义

将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器。比如:是指如果一个接口需要B接口,但是待传入的对象却是A接口,这时就可以用适配器模式。生活场景:如果去美国,我们随身带的电器是无法直接使用的,因为美国的插座标准和中国不同,所以,我们需要一个适配器。

3.2. 适配器模式的使用

3.2.1. 包含的角色

1. 源对象(Adaptee):已有的类或对象,其接口与目标接口不兼容,需要被适配器转换为目标接口。

  1. 目标接口(Target interface):客户端所期望的接口,即客户端想要调用的接口。
  2. 适配器(Adapter):将源对象转化为目标接口。

3.2.2. 两种实现方式:

  1. 类适配器:继承源,实现目标接口
    image.png
    2. 对象适配器:适配器持有源的实例对象
    image.png

3.2.3. 使用

1. MQ中不同MQ消息的适配思想的应用(思想)比如说订单信息的MQ,内部订单可能用户ID为UserID,第三方订单的用户ID为uid。这样两个MQ消息需要两个类来消费。如果你的MQ量不多,这样的写法也没什么问题,但是随着数量的增加,就需要考虑用一些设计模式来解决。适配器模式要解决的主要问题就是多种差异化类型的接口做统一输出。源MQ(多种):
image.png
 
image.png
 目标:
image.png
 适配器:
image.png
 测试:
image.png
 
image.png
2. SpringMVC中适配器的使用
  1) 用户发起一个 HTTP 请求到 Spring MVC 应用。
2) DispatcherServlet 接收到请求后,首先会调用 HandlerMapping,寻找合适的处理器(Handler)来处理这个请求。
3) 找到合适的处理器后,DispatcherServlet 需要找到一个能够处理这个处理器的 HandlerAdapter。为此,它会遍历所有已注册的 HandlerAdapter,调用它们的 supports 方法,检查它们是否支持当前处理器。
4) 找到支持当前处理器的 HandlerAdapter 后,DispatcherServlet 会调用该 HandlerAdapter 的 handle 方法,将请求委托给处理器进行处理。
5) 处理器处理完请求后,会返回一个 ModelAndView 对象,DispatcherServlet 会将这个对象传递给适当的 ViewResolver,以解析视图并将响应返回给用户。

以上两个重要的类;Handler和HandlerAdapter。Handler有多种,对应的HandlerAdapter也有多种,通过遍历所有HandlerAdapter集合找到支持当前Handler的HandlerAdapter。

HandlerAdapter:

public interface HandlerAdapter { 
   boolean supports(Object handler);   
     ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
} 

CustomHandler:

public class CustomHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return handler instanceof CustomHandler;
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        CustomHandler customHandler = (CustomHandler) handler;
        String result = customHandler.handleRequest();
        return new ModelAndView("customView", "message", result);
    }
    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }
}

 在SpringMVC中自定义HandlerAdapter需要进行注册到DispatcherServlet :

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addAdapters(List<HandlerAdapter> adapters) {
        adapters.add(new CustomHandlerAdapter());
        super.addAdapters(adapters);
    }
}

3.3. 适配器模式优点

1.将目标类和适配者类解耦2、增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性3、灵活性和扩展性都非常好,符合开闭原则。

3.4. 适配器模式缺点

1、对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为接口,不能为类,其使用有一定的局限性,不能将一个适配者类和他的子类同时适配到目标接口。 

4. 观察者模式

4.1. 定义

如果某个对象的改变会引起其它很多对象的改变,就可以用观察者模式。观察者模式定义了对象之间一对多的关系,当一个对象改变后,其他对象都会收到通知。又称发布订阅模式。

4.2. 观察者模式的使用

4.2.1. 包含的角色

1. 主题(被观察者)
2. 观察者:抽象观察者和具体观察者

4.2.2. 使用

例如订单系统,当发生订单取消时,账户业务要给用户退钱,库存业务需要退回数量。
1. 手写观察者模式
1)主题:持有观察者的集合
image.png
2)观察者:抽象观察者和具体观察者
image.png
 账户业务观察者:
image.png
库存业务观察者:
image.png
 3)客户端触发主题(主题持有者):
image.png
2. Spring观察者模式(spring中称为事件监听)
1)角色
1、 事件:继承自ApplicationEvent类
2、 事件监听器:定义一个处理事件的方法,添加 @EventListener注解,参数类型为用户注册的事件类的对象
3、 事件发布器:调用ApplicationEventPublisher 对象发布事件
2)使用
事件:
image.png
 账户监听器:
image.png
 库存监听器:
image.png
 事件发布:
image.png

4.3. 观察者模式优点

1、观察者模式在被观察者和观察者之间建立一个抽象的耦合。
2、观察者模式支持广播通讯

4.4. 观察者模式缺点

1、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。

4.5 观察者模式跟事件监听模式的区别:

  1. 设计模型的对比,可以通过uml图的方式直观对比 参考文章

5. 享元模式

5.1. 定义

主要在于共享通用对象,减少内存的使用,提升系统的访问效率。而这部分共享对象通常比较耗费内存或者需要查询大量接口或者使用数据库资源,因此统一抽离作为共享对象使用。在享元模型的实现中需要使用到享元工厂来进行管理这部分独立的对象和共享的对象,避免出现线程安全的问题。

5.2. 享元模式使用

 5.3. 享元模式优点

 5.4. 享元模式缺点


everynewtry
17 声望1 粉丝