0428-Spring事件驱动(1-观察者模式)

前情提要

https://www.jianshu.com/p/593e4d127093

上一个小作文中,我们通过接口的形式实现了JAVA的回调函数,做到了一对一的消息通知或者说方法调用,"下载器只需要通知迅雷对象,实际可能会通知多种对象",按照上一节的思路实现一个下载器通知多个对象,下载器需要聚合多个对象,并且还要考虑聚合对象的初始化问题,按照这个思路是不容易实现,一对多的方法调用的。
想要实现一方调用多方的方法该具备怎样的条件?
1.一方应该持有多方的引用
2.多方应该有相同的方法调用入口

普通实现

public class One{
    DualA a;
    DualB b;
    //***省略多方
  public initA(DualA a){
      this.a = a;
  }
  public initB(DualB b){
      this.b = b;
  }


   public void toInvokeMethod(){
    a.methodA();
    b.methodB();
    //....
  }
  public static void main(String[] args){
      One one = new One();
      one.initA(new A());
      //....
      one.toInvokeMethod();
  }
}
public class DualA {
  void methodA(){}
}
public class DualB {
  void methodB(){}
}

从上述的代码中可以清晰的看出这些问题:
Q1.如果有更多的多方需要被调用,需要组合更多类
Q2.需要调用太多不同的init方法为引用赋值(不然会空指针)

怎样可以做到调用一个方法解决引用赋值的问题(组合类太多、赋值方法太多)?
所有类都有一个父类Object,可以组合一个Object的集合解决组合类太多问题,赋值方法太多也顺便解决。

public class One{
    List<Object> list
    void initList(Object o){  //void initA(A a) {this.a = a}
        list.add(o);
    }
    void toInvokeMethod(){
      
    }
}

这个时候toInvokeMthod如何实现?
遍历集合!取出Object对象,会发现没有我们需要调用的方法,使用多态的思想,多方实现一个公共的接口,各自重写里边的调用方法,这样遍历后就可以满足要求。

public interface ObserverInterface {
    void update(Object o);
}

public class Observer1 implements ObserverInterface{
    @Override
    public void update(Object o) {
        System.out.println("o1 do something");
    }
}

public class Observer2 implements ObserverInterface{
    @Override
    public void update(Object o) {
        System.out.println("o2 do something");
    }
}

public class Subject{
  List<ObserverInterface> list;

  public void addObserver(ObserverInterface o){
    list.add(o);
  }

  public void notify(){
    list.foreach(item -> item.update(new Object())) ;//可以传基本数据类型,引用数据类型
  }
public static void main(String[] args){
   ObserverInterface  o1 =  new Observer1();
    ObserverInterface  o2 =  new Observer2();
    Subject sub = new Subject();
    sub.addObserver(o1);
    sub.addObserver(o2);
    sub.notify();
}
}

可以看出问题,在subject的notify方法调用的update没起到传递有效数据的效果,这些数据只能写死,该如何解决死数据的问题呐?

 list.foreach(item -> item.update(new Object()));
 list.foreach(item -> item.update(1)) ;
 list.foreach(item -> item.update("ABC")) ;

1.让subject这个对象有属性,通过方法为属性赋值,将subject当作参数传递,这样在update时数据就不是死的

public class Subject implements SubjectInterface{
    String name;
    public Subject(String name){
        this.name = name;
    }
//....省略相同代码
    public boolean notifyObserver() {
        if(observers == null){
            return false;
        }
        observers.forEach(item -> item.update(this));
        return true;
    }
}

public class Observer1 implements ObserverInterface{
   
    public void update(Object o) {
        String name = (String) o;
        System.out.println("o1 do something" + " name:"+name);
    }
}

public static void main(String[] args){
   ObserverInterface  o1 =  new Observer1();
    ObserverInterface  o2 =  new Observer2();
    Subject sub = new Subject("zhangsan");
    sub.addObserver(o1);
    sub.addObserver(o2);
    sub.notify();
}

2.构造一个数据对象

public class Data{
    String name;
}

void update(Data data){}

void notify(Data data){
  observers.forEach(item -> item.update(data));
}

Data d = new Data("zhangsan");
subject.notify(d);//完成调用

类图

观察者类图.jpg

思考:用户在系统中刚注册,需要为用户初始化积分和个人设置,该如何实现。

观察者模式实现
1.获取被观察者(主题)
2.获得观察者
3.将观察者和被观察者绑定
4.被观察者(主题)调用通知方法
5.观察者调用方法

public class Main {
    public static void main(String[] args) {
        RegisteSub concurrentSubject = new RegisteSub();
        ObserverInterface pointsObserver = new PointsObserver();
        UserObserver userObserver = new UserObserver();
        concurrentSubject.addListener(pointsObserver);
        concurrentSubject.addListener(userObserver);

        RegisterService registerService = new RegisterService();
        boolean success = registerService.registerByTel();
        if(success){
            concurrentSubject.notifyObserver();
        }

}

主题和主题接口

public interface SubjectInterface {
    boolean addListener(ObserverInterface observer);
    boolean removeListener(ObserverInterface observer);
    void notifyObserver();
}
public class RegisteSub implements SubjectInterface{

    List<ObserverInterface> observers;

    @Override
    public boolean addListener(ObserverInterface observer) {
        if(observers == null){
            observers = new ArrayList<>();
        }
        return observers.add(observer);
    }

    @Override
    public boolean removeListener(ObserverInterface observer) {
        if(observers!=null){
            return observers.remove(observer);
        }
        return false;
    }

    @Override
    public void notifyObserver() {
        observers.forEach(item -> item.update(this));
    }

    void registerUserByTel(String tel){
        System.out.println(tel + "注册成功");
        notifyObserver();
    }
}

观察者和观察者接口

public interface ObserverInterface {

    void update(Object o);
}

public class PointsObserver implements ObserverInterface{
    @Override
    public void update(Object o) {
        System.out.println("积分系统:初始化!");
    }
}

一般实现

public class registeController{
      @Override
      RegisterService registerService;
      @Override
      PointsService pointsService;
      @Override
      UserService userService;

      public void regitser(String tel){
              boolean success = registerService.registeByTel(tel);//
              if(success){ //注册成功,则调用积分服务和个人设置服务的初始化方法
                  pointsService.init(tel);
                  userService.init(tel);
              }
      }
      static class RegisterService{
       public  boolean registerByTel(){
            return true;
        }
    }

}

开发中这样实现功能的代码应该是最为普遍的,假设现在有新需求:当注册成功后,需要初始化用户的好友列表,在上述代码基础上,我们不得不修改类,为其注入新的服务,并修改方法的调用,这样违背了开闭原则。在不使用MQ和违背开闭原则的基础上,我们该如何实现这个需求呐?敬请期待!使用观察者模式的订阅发布模型实现的事务驱动(spring 简版)!

引用博客

https://zhuanlan.zhihu.com/p/431748712 #类图是偷的这个哥们的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容