不同的設計模式———觀察者模式

前言

這個東西寫用的少,框架中用的多。有一次面試中,遇到了,平時我沒有用過,如今整理一下。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 processes;,能夠替換成委託。

上面的代碼還有一個問題就是:

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

觀察者模式有不少實現方式,各有優點。

相關文章
相關標籤/搜索