觀察者模式

在處理類之間的多對一的依賴關係時,觀察者設計模式應運而生了,它的出現實現了代碼的瘦身,類之間的解耦,本文分三部分:前端

  • 非觀察者模式的多對一的依賴處理
  • 觀察者模式對多對一依賴處理的優化
  • Java內置的觀察者

假設場景: 前端用戶向後端服務器發送不一樣的請求,後端的Selector區的分不一樣的請求,回調不一樣的Handler處理請求, 下面的示例代碼java

非觀察者

當Selector發現數據改變時,想要回調Handler的方法的前提是它要維護一個Handler的引用, 咱們在構造函數中傳遞進去後端

@Data
public class Selector {
    private String username; 
    private String password; 

    private Handler1 currentConditions;

    public Selector(Handler1 currentConditions) {
        this.currentConditions = new Handler1();
    }

    public void datachange() {
        currentConditions.update(getUsername(),getPassword());
    }

    // 添加假數據
    public void setData(String username,String password){
        this.username=username;
        this.password=password;
        datachange();
    }

}

Handkler 的成員變量和Selector同樣, 同時真正幹活的人是handler, 它裏面只有幹活的方法以及承載數據的字段, 幹活的方法會被回調, 字段由Selector負責初始化設計模式

public class Handler1 {
    private String  username;
    private String password;

    public void update( String  username, String  password){
        this.username=username;
        this.password=password;
        display();
    }

    public void display(){
        System.out.println("Handler1 : username"+ username);
        System.out.println("Handler1 : password"+username);
    }
}

測試:服務器

public class text {
    public static void main(String[] args) {
        Handler1 currentConditions = new Handler1();
        Selector weatherData = new Selector(currentConditions);
        weatherData.setData("張三","123");
    }
}

上面的設計方法實現了,當Selector發現新的數據改變時,回調指定的handler的需求,可是缺點很快就暴露出來, Handler引用以構造方法的形式在Selector維護,若是有100個handler, 是否是意味着Selector的構造函數重載100份?ide


觀察者模式

觀察者解決了上面的問題,在觀察者模式中有兩個角色的劃分,1.SubJect 2.Observer, 其中 SubJect負責回調Observer提供的方法處理數據, Observer就是觀察者,乘機而動, 它之因此可以實現二者的解耦,實現代碼的瘦身,精華就是在Subject的構造函數再也不維護單一的某一個Observer的引用,而是一個泛型是爲Observer類型的集合, 爲了防止把非觀察者的對象添加到集合中, 故 在原有的基礎上,向上進行了一層抽象,把Subject和Observer設計成接口,Subject提供了註冊/移除/通知觀察者的方法,通知哪一個方法呢? 因而Observer接口中提供了須要被回調的抽象方法, 作完這層封裝以後,就有了這個觀察者體系, 全部的觀察者必須實現Observer接口,重寫它的方法,任何回調觀察者的類,也必須實現Subject,重寫它的方法函數

實例代碼:測試

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObserver();
}

public interface Observer {
    public void update(String m,String p);
}

Subject的實現類:優化

@Data
public class Selector implements Subject {
    private String username;
    private String password;

    private ArrayList<Observer> list;

    public Selector() {
      this.list = new ArrayList<Observer>();
    }

    // 添加假數據
    public void setData( String username, String password){
        this.username=username;
        this.password=password;

    }

    @Override
    public void registerObserver(Observer o) {
        list.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        list.remove(o);
    }

    @Override
    public void notifyObserver() {
        list.forEach(s->s.update(getPassword(),getUsername()));
    }
}

Observer的實現:this

public class Handler1 implements Observer {
    private String username;
    private String password;

    @Override
    public void update( String username,String password){
        this.username=username;
        this.password=password;
        display();
    }

    public void display(){
        System.out.println("  Handler1    "+ username);
        System.out.println("  Handler1    "+password);
    }
}

測試:

public class text {
    public static void main(String[] args) {
        Handler1 secondConditions = new Handler1();
        Selector weatherData = new Selector();
        // 註冊觀察者
        weatherData.registerObserver(secondConditions);
        weatherData.setData("張三","123");
        weatherData.notifyObserver();
    }
}

咱們本身實現的觀察者函數回調的特性: : 雖然實現咱們一開始的需求,可是能夠看到,數據是在Subject端進行初始化的, 並無傳遞到觀察端,由觀察者自主分配數據


java內置的觀察者

java內置的觀察中一樣分爲兩種角色,1.Obserable 2.Observer 其中Observer是觀察者,一樣不變的是,他是個接口

可是: Obserable是一個抽象類, java爲咱們實現了 註冊/移除,通知的方法, 在不容許多繼承的java中,抽象類是有缺點的,這使得當前類不能再繼承其餘類

此外: 相對於咱們自定義的觀察者, 它作到了把數據傳遞到 觀察者客戶端,任由觀察者自主的分配這些數據

如何使用:
對於Obserable來講, 繼承他

  • 因爲java實現了主要的方法, 咱們只關注如何使用這幾個方法就好了
  • 1: 在回調以前 , 必須先使用 this.setChanged(); 不然信息不會通知到觀察者
  • 2: 通知的方法this.notifyObservers(Object obj));
@Data
public class Selector extends Observable {
    private String username;
    private String  password;

    // 添加假數據
    public void setData( String username, String password) {
        this.username = username;
        this.password = password;
        datachange();
    }

    // 當信息更改, 就推送
    public void datachange() {
        // todo 加上這一條,當有信息改變時, 就執行
        this.setChanged();
        // 通知時,把信息同步推送給觀察者
       this.notifyObservers(new Data(getUsername(),getPassword()));
    }

    @lombok.Data
    public class Data {
        private String username;
        private String  password;

        public Data( String username, String password) {
            this.username = username;
            this.password = password;
        }
    }
}

觀察者: 繼承Observer, 重寫它被回調的方法

public class Handler1 implements Observer {
    private String username; 
    private String password;  

    @Override
    public void update(Observable observable, Object arg0) {
        this.password = ((Selector.Data) (arg0)).getPassword();
        this.username = ((Selector.Data) (arg0)).getUsername();
        display();
    }

    public void display() {
        System.out.println("Handler1 :    " + username);
        System.out.println("Handler1 : " + password);
    }
}

測試

public class text {
    public static void main(String[] args) {
        Handler1 handler1 = new Handler1();
        Selector weatherData = new Selector();
        // 先註冊的觀察者,後執行
        weatherData.addObserver(handler1);
        weatherData.setData("張三","123");
    }
}
相關文章
相關標籤/搜索