這個東西寫用的少,框架中用的多。有一次面試中,遇到了,平時我沒有用過,如今整理一下。html
觀察者模式解決的問題是什麼?mysql
有這樣的一種場景,好比說一個對象的狀態發生改變,全部的依賴對象將會獲得通知。面試
模型以下:sql
就是這樣一個境地,那麼問題來了,這樣耦合性就大,好比說我要添加一個觀察者,那麼改動的對象就是被監聽對象。框架
也就是說監聽對象不穩定,這裏問題就很是大,通常看到這個時候呢,其實100%須要重構。由於鏈接線最多的地方基本上要是穩定的。this
觀察者模式就是來下降耦合。code
手寫代碼,沒有通過驗證,只是介紹思想。orm
上面的例子是文件切割,而後進度條反饋進度。server
public class FileSplitter { string pathName; ProccessBar processbar; Public FileSplitter(string pathName) { this.pathName=pathname; } public void splitter() { //處理事務.... processbar.setvalue(xx); } }
這裏有個問題,那就是ProccessBar processbar;是面向具體實現類。htm
這裏考慮是否進度條的種類會發生變化?可能有不一樣的進度條。
那麼能夠把進度條傳遞進來:
public class FileSplitter { string pathName; ProccessBar processbar; Public FileSplitter(string pathName,ProccessBar processbar) { this.pathName=pathname; this.processbar=processbar; } public void splitter() { //處理事務.... processbar.setvalue(xx); } }
FileSplitter 依賴於ProccessBar 的具體實現,這個時候就有個問題,由於ProccessBar 是winform的組件,這樣沒法複用。
還有一個問題,那就是進度條和FileSplitter耦合了,耦合是能夠的,可是這二者並不相關,他們不該該存在耦合。
是啊,文件分割和進度條他們之間沒有關係啊。
這個時候可能提出那麼把ProccessBar去面向接口吧,不面向具體實現類。這個時候是不徹底對的,面向接口抽象是爲了延遲實現,可是這二者自己就不該該耦合。
那麼這個時候就開始分析ProccessBar processbar;究竟是作什麼的?
ProccessBar 是進度條,進度條是什麼?進度條是展示給人們看的進度。
這個時候抓住一個關鍵點在於,對於FileSplitter來講須要的只是一個進度通知,而不是一個進度條。
interface Iprogress{ void showProgress(float value); } public class FileSplitter { string pathName; Iprogress process; Public FileSplitter(string pathName) { this.pathName=pathname; } public void splitter() { //處理事務.... if(process!=null) { process.showProgress(...); } } }
這個時候就很好了,這個時候就是帶通知的文件系統,是一個總體。
這個時候還有一個問題,那就是既然是進度通知,那麼通知的對象就不單單是一個,還有一個問題就是process如何傳進來,那麼能夠改一下。
interface Iprogress{ void showProgress(float value); } public class FileSplitter { string pathName; List<Iprogress> processes; Public FileSplitter(string pathName,ProccessBar process=null) { this.pathName=pathname; this.processes=new List<IProgress>; } public void addProcess(Iproccess proccess) { processes.add(proccess); } public void RemoveProcess(Iproccess proccess) { processes.remove(proccess); } public void splitter() { //處理事務.... foreach(var proccess in processes) { process.showProgress(...); } } }
那麼要使用ProccessBar,這樣寫:
class mysql:form,Iprogress { ProccessBar proccessbar; void dosomething() { FileSplitter f=new FileSplitter (); f.addProcess(this); } //具體實現 void showProgress(float value) { proccessbar.setValue(value); } }
不少人看到觀察者想到了委託,很大一部門緣由是List
上面的代碼還有一個問題就是:
public void splitter() { //處理事務.... foreach(var proccess in processes) { process.showProgress(...); } }
違法了單一原則。
由於切割對象又作了通知,那麼能夠這樣。
public void splitter() { //處理事務.... noticeProcesses(); } protect void noticeProcesses() { foreach(var proccess in processes) { process.showProgress(...); } }
那麼這裏還有一個問題,就是進度通知不少類都須要,那麼如何把:
public void addProcess(Iproccess proccess) { processes.add(proccess); } public void RemoveProcess(Iproccess proccess) { processes.remove(proccess); } protect void noticeProcesses() { foreach(var proccess in processes) { process.showProgress(...); } }
這一部分移出去?不少人考慮到把進度封裝成一個類,而後讓具體實現類繼承就能夠。
觀察者模式的好處:
1.無需指定觀察者,通知會自動傳播。
2.觀察者本身實現訂閱機制,而目標對象本身不知道。調用noticeProcesses便可。
還有這種實現方式,https://www.runoob.com/design-pattern/observer-pattern.html
觀察者模式有不少實現方式,各有優點。