0428-Spring事件驅動(1-觀察者模式)

前情提要

http://www.itdecent.cn/p/593e4d127093

上一個小作文中,我們通過接口的形式實現了JAVA的回調函數,做到了一對一的消息通知或者說方法調用,"下載器只需要通知迅雷對象,實際可能會通知多種對象",按照上一節(jié)的思路實現一個下載器通知多個對象,下載器需要聚合多個對象,并且還要考慮聚合對象的初始化問題,按照這個思路是不容易實現,一對多的方法調用的。
想要實現一方調用多方的方法該具備怎樣的條件?
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對象,會發(fā)現沒有我們需要調用的方法,使用多態(tài)的思想,多方實現一個公共的接口,各自重寫里邊的調用方法,這樣遍歷后就可以滿足要求。

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;
        }
    }

}

開發(fā)中這樣實現功能的代碼應該是最為普遍的,假設現在有新需求:當注冊成功后,需要初始化用戶的好友列表,在上述代碼基礎上,我們不得不修改類,為其注入新的服務,并修改方法的調用,這樣違背了開閉原則。在不使用MQ和違背開閉原則的基礎上,我們該如何實現這個需求吶?敬請期待!使用觀察者模式的訂閱發(fā)布模型實現的事務驅動(spring 簡版)!

引用博客

https://zhuanlan.zhihu.com/p/431748712 #類圖是偷的這個哥們的

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容