Java-第十八部分-设计模式-策略模式和职责链模式

379 阅读3分钟

设计模式全文

策略模式

  • 案例,鸭子有多种,有多个行为

不同种的鸭子,所具有的行为也不同,无法很好地用抽象层统一

  • Strategy Pattern,定义算法簇,分别封装,让算法之间可以相互替换,让算法的变化独立于使用算法的客户端
  1. 把变化的代码从不变的代码中分离出来
  2. 针对接口编程
  3. 将继承转换成组合/聚合,少用继承
  4. 把算法的使用者和提供者解耦 demo2.png
  • 案例类图,把每类行为提取出来,作为附属接口,按需实现 demo3.png
  • 飞行策略
public interface FlyBehavior {
    void fly();
}
  • 策略具体实现
public class GoodFlyBehavior implements FlyBehavior{
    @Override
    public void fly() {
        System.out.println("GoodFlyBehavior");
    }
}
  • 鸭子抽象类,聚合了飞行策略
public abstract class Duck {
    FlyBehavior flyBehavior;
    public abstract void display();
    public void fly() {
        if (flyBehavior != null) {
            flyBehavior.fly();
        }
    }
}
  • 野鸭类,决定具体的飞行策略
public class WildDuck extends Duck{
    public WildDuck() {
        flyBehavior = new GoodFlyBehavior();
    }
    @Override
    public void display() {
        System.out.println("WildDuck");
    }
}

Arrays源码

  • Comparator中使用了策略模式
  • 匿名类对象,实现了Comparator接口的策略
Comparator<Integer> comparator = new Comparator<Integer>() {
    public int compare(Integer o1, Integer o2) {
        if (o1 > o2) {
            return -1;
        } else {
            return 1;
        }
    };
};
  • 将这个策略传入
Arrays.sort(data, comparator);

image.png

小结

  • 分析对象中变化的部分和不变的部分,对修改关闭,对扩展开放,将算法封装在独立的Strategy中,利于扩展
  • 多用聚合/组合,少用继承,用行为类组合,避免行为的继承
  • 策略过多,导致类数目扩大

职责链模式

  • 案例,学校采购,不同的金额,需要不同级别的领导来审核
  • Chain of Responsibility Pattern,责任链模式,行为型模式,为请求创建一个接受者的处理链,将请求发送者和接受者进行解耦
  • 每一个接受者都包含下一个接受者,一个接受者对象不同处理该请求,将请求传给下一个接受者 demo.png
  • 案例类图 oa.png
  • 处理者抽象类
public abstract class Approver {
    Approver approver;
    String name;
    public Approver(String name) {
        this.name = name;
    }
    public void setApprover(Approver approver) {
        this.approver = approver;
    }
    abstract void processRequest(PurchaseRequest purchaseRequest);
}
  • 其中一个的实现,在使用时需要设置下一级处理者,避免为空
public class CollegeApprover extends Approver{
    public CollegeApprover(String name) {
        super(name);
    }
    @Override
    void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <= 10000) {
            System.out.println(purchaseRequest.getId() + " - " + name);
        } else {
            approver.processRequest(purchaseRequest);
        }
    }
}
  • 请求
public class PurchaseRequest {
    private int type = 0; //类型
    private float price = 0.0f; //金额
    private int id = 0; //编号
    public PurchaseRequest(int type, float price, int id) {
        this.type = type;
        this.price = price;
        this.id = id;
    }
}

SpringMVC中的应用

  • SpringMVC处理流程 IMG_4E2A3DC669CB-1.jpeg
  1. 接受request
  2. 找到对应的HandlerMapping,并得到HandleExecutionChain和其中的拦截器HandlerInterceptor
  3. HandlerInterceptor依次调用preHandle、postHandle、afterCompletion
  • DispatcherServlet中的doDispatch,也运用到了适配器模式 image.png
  • 获取HandlerExecutionChain,主要负责请求拦截器的执行和请求处理,本身不处理请求,将请求分配给链上注册的处理器执行,减少了职责链本身与处理逻辑之间的耦合,规范处理流程

维护了HandlerInterceptor集合,可以向其中注册拦截器 image.png

  • 调用applyPreHandle image.png
  • 拿到HandlerInterceptor拦截器 image.png
  • 调用applyPostHandle image.png
  • 调用postHandle image.png
  • interceptorIndex记录了上一轮执行的拦截器,当postHandle返回true,会保存下来,当期间某一个拦截器的postHandle返回false,会倒序调用前面的拦截器的afterCompletion方法 image.png
  • applyPreHandle方法中调用的triggerAfterCompletion,调用了afterCompletion image.png
  • processDispatchResult最后也会执行afterCompletion image.png image.png
  • 过程中发生异常后,也会执行afterCompletion image.png

小结

  • 将请求和处理分开,实现解耦,提高灵活性
  • 性能会受到影响,要在Handler设置一个最大节点数量,过长会破坏性能
  • 适用于多个对象处理同个请求,多级请求、请加/加薪等审批业务、javaWeb中tomcat对Encoding的处理、拦截器