【设计模式3_责任链、观察者】

责任链

有如下业务场景,需要对请求接口做一系列的校验,那么很容易写出以下伪代码,利用抛出异常拦截错误请求参数:

    public static void main(String[] args) {
        // ...
        try{
            checkSecurity();
            checkParams();
            checkRule();
        } catch (Exception e){
            // ...
        }
    }

    private static void checkSecurity(){
        // ...
        throw new RuntimeException();
    }

    private static void checkParams(){
        // ...
        throw new RuntimeException();
    }

    private static void checkRule(){
        // ...
        throw new RuntimeException();
    }

使用异常来校验,那么后续逻辑越来复杂的话:
如异常只能返回异常信息,不能返回更多字段,这时候需要自定义异常类。
异常的处理效率比条件判断的方式低很多。异常设计的初衷是解决程序运行中的各种意外情况,不应该用来做流程控制、条件控制。

这时候可以使用责任链模式

责任链模式为请求的接收创建了一个执行链,链上有多个节点,每个节点都有可能满足条件匹配然后处理请求事务。当某个节点处理完了,可以根据业务需求传递给下一个节点继续处理或返回处理完毕。

一,利用模版方法准备一个抽象类,作为所有责任节点的父类,在这个类里:

  1. 一个指向下一个责任节点属性
  2. 一个设置下一个对象的set方法
  3. 完成当前节点后链接到下一节点的逻辑
  4. 给子类提供差异化实现的抽象方法
public abstract class AbstractHandler {

    // 指向下一个责任节点属性
    private AbstractHandler nextHandler;

    // 设置下一个对象的set方法
    public void setNextHandler(AbstractHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public AbstractHandler getNextHandler() {
        return this.nextHandler;
    }

    // 留给子类做差异化实现
    abstract boolean doFilter();

    // 对外提供的入口
    public boolean filter(){
        // 执行本节点的逻辑。如果校验通过则继续下节点,失败则直接返回
        boolean b = doFilter();
        if(b) {
	        // 指向下一节点,如果下节点为空则代表当前就是最后一个节点
	        if (this.nextHandler != null){
	            return this.nextHandler.filter();
	        }else {
	        	return false;
	        }
		} else {
			return false;
		}

    }
    
}

各实现类:

@Component
@Order(1)
public class CheckSecurityHandler extends AbstractHandler {
    @Override
    boolean doFilter() {

    }
}
@Component
@Order(1)
public class CheckRuleHandler extends AbstractHandler {
    @Override
    boolean doFilter() {

    }
}

一次性初始化所有的责任链对象(不是必须)

@Component
public class ChainOfResponseDemo {

    @Autowired
    private List<AbstractHandler> abstractHandlerList;


    private AbstractHandler abstractHandler;

    /* @PostConstruct注解的方法在项目启动的时候执行这个方法,
      也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。
    * */
    @PostConstruct
    public void initializeHandlerChain(){

        for (int i = 0; i < this.abstractHandlerList.size(); i++) {
            if ( i == 0){
                abstractHandler = abstractHandlerList.get(0);
            } else {
                AbstractHandler lastHandler = abstractHandlerList.get(i - 1);
                AbstractHandler nextHandler = abstractHandlerList.get(i);
                lastHandler.setNextHandler(nextHandler);
            }
        }
    }

    // 对外提供的入口
    public boolean execute(){
        return abstractHandler.filter();
    }


    public AbstractHandler getAbstractHandler() {
        return abstractHandler;
    }

    public void setAbstractHandler(AbstractHandler abstractHandler) {
        this.abstractHandler = abstractHandler;
    }
}

方法使用@PostConstruct 执行顺序:
其实从依赖注入的字面意思就可以知道,要将对象p注入到对象a,那么首先就必须得生成对象a和对象p,才能执行注入。
所以,如果一个类A中有个成员变量p被@Autowried注解,那么@Autowired注入是发生在A的构造方法执行完之后的。
如果想在生成对象时完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么久无法在构造函数中实现。
为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。

        Constructor >> @Autowired >> @PostConstruct

当然也可以不用一次初始化所有责任链对象,而是在使用时,再将需要用到的责任对象创建、灵活组合排序。
参考:https://blog.csdn.net/cui_yonghua/article/details/93462893

观察者

当发生一个事件时,根据需求要触发多个不同操作,就可以用观察者模式实现类似 发布-订阅的模式。

用一个Subject类:

  1. 有一个成员变量 容器 List
  2. 有一个方法去通知容器里现存的所有观察者类
  3. 向容器中 添加/移除 观察者的方法

所有的观察者,可以统一继承一个抽象类,各自都要自己实现接收通知的方法体。
需要用到的哪些观察者,都可以在客户端自行向Subject中的容器加入(订阅),就可以被Subject通知到

Subject类:

public class Subject {

    private List<AbstractObserver> container = new ArrayList<>();

    public void notifyAllObserver(String...args) {
        for (AbstractObserver observer : container) {
            observer.observed(); // 对容器中现存的观察者逐一通知
        }
    }

    public void addObserver(AbstractObserver observer) {
        this.container.add(observer);
    }

    public void removeObserver(AbstractObserver observer) {
        this.container.remove(observer);
    }

}

观察者

public abstract class AbstractObserver {
    public abstract void observed();
}

public class TaskObserver1 extends AbstractObserver {
    @Override
    public void observed() {
        System.out.println("TaskObserver1...被通知到,我要开始睡觉了");
    }
}

public class TaskObserver2 extends AbstractObserver {
    @Override
    public void observed() {
        System.out.println("TaskObserver2...被通知到,我要开始学习了");
    }
}

客户端。使用演示

    public static void main(String[] args) {

        Subject subject = new Subject();
        TaskObserver1 taskObserver1 = new TaskObserver1();
        TaskObserver2 taskObserver2 = new TaskObserver2();

        subject.addObserver(taskObserver1);
        subject.addObserver(taskObserver2);

        subject.notifyAllObserver();

    }

扩展功能:
可以灵活的将 taskObserver1 添加或移除,以适应不同的业务场景。这一步还可以根据简单工厂,抽取成不同场景下需要通知不同观察者的固定实现。

notifyAllObserver 方法里也可以根据参数,选择性通知不同的observer。

observed() 方法也可以设置参数,如observed(AbstractObserver observer),可以实现,当一个observer收到消息时,再动态的对一个observe做添加或移除…等操作。

你可能感兴趣的:(Java,设计模式,java)