在處理類之間的多對一的依賴關係時,觀察者設計模式應運而生了,它的出現實現了代碼的瘦身,類之間的解耦,本文分三部分:前端
假設場景: 前端用戶向後端服務器發送不一樣的請求,後端的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內置的觀察中一樣分爲兩種角色,1.Obserable 2.Observer 其中Observer是觀察者,一樣不變的是,他是個接口
可是: Obserable是一個抽象類, java爲咱們實現了 註冊/移除,通知的方法, 在不容許多繼承的java中,抽象類是有缺點的,這使得當前類不能再繼承其餘類
此外: 相對於咱們自定義的觀察者, 它作到了把數據傳遞到 觀察者客戶端,任由觀察者自主的分配這些數據
如何使用:
對於Obserable來講, 繼承他
this.setChanged();
不然信息不會通知到觀察者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"); } }