本文關鍵詞:觀察者模式。segmentfault
觀察者模式是什麼?
觀察者模式和回調函數有什麼關係?
使用httpClient時,加上.subscribe有什麼做用?
Angular的httpClient中如何體現觀察者模式?設計模式
解決了上述問題以後,就寫了這篇文章。函數
(這篇文章其實是給上一篇文章填個坑...上一篇寫到回調函數,卻沒有給出實際應用的例子。)學習
httpClient是Angular中的一個內置類,用於向後臺發起Http請求、返回請求結果。用它來舉例子是由於功能比較簡單,易於理解。this
在Angular中有這麼一種寫法:url
// 向8080端口的helloWorld路徑發起請求 httpClient.get('http://localhost:8080/helloWorld') .subscribe((data) => { console.log('請求成功'); console.log(data); }, error); }
不經意一看,這不就是簡單的鏈式調用麼?——前一個方法返回一個對象,再調用這個對象的方法,再返回對象,再調用方法...
可是仔細看,才發現:這根本就不是一個過程,而是兩個過程啊!
從使用.get向後臺發起請求以後,到調用.subscribe以前,這之中經歷了一個後臺接收數據、處理數據、返回數據的過程。spa
那麼問題來了:挖掘機技術哪家強?前臺如何知道數據何時返回?怎麼在數據返回以後,自動執行後面的代碼來打印返回數據?設計
觀察者模式,顧名思義,有這樣一個對象,在始終被另外一個對象觀察着、注視着、牢牢的盯着。
用雜誌社作比喻:有一個雜誌社,雜誌社裏有一個訂閱報刊的部門,一個讀者向這個部門訂閱了雜誌,今後之後讀者日日期盼着讀到本身買的雜誌,而訂閱部門也會在新的雜誌出版以後,第一時間送到讀者手裏。
這就是觀察者模式,它由兩部分組成:
數據源 + 訂閱者 = 觀察者模式
數據源和訂閱者之間是一對多的關係。訂閱者經過某種方法,向數據源發起訂閱,此後,數據源一旦發生變動,會立刻通知全部的訂閱者。code
既然知道了原理,那麼在httpClient中具體是怎麼實現的呢?
咱們找到源碼,httpClient類的全部方法都寫在裏面,而且有一大堆重載:
server
咱們拿出一個方法來看看:
/** * Constructs a `GET` request that interprets the body as a text string * and returns the response as a string value. * * @param url The endpoint URL. * @param options The HTTP options to send with the request. * * @return An `Observable` of the response, with the response body of type string. */ get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: 'body'; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType: 'text'; withCredentials?: boolean; }): Observable<string>;
把代碼格式化一下,變成咱們容易理解的方式:
能夠看到get方法的必填參數是請求地址URL,還有可選參數。但這些都不重要,關鍵在於,普通的方法,用方法名+參數就完事了,好比:
test();
再看這個方法的最後,多出了一個: Observable<string>這是觀察者的關鍵!這條代碼的意思是:返回類型爲「觀察者」的對象,這個觀察者攜帶着string類型的被觀察的數據。
Observable是「可觀察的」意思,聲明一個方法有可觀察的對象以後,這個方法的返回值就再也不是一個普通變量,而是一個「觀察者」對象,咱們對這個對象使用.subscribe方法訂閱,就能夠傳入函數進行回調了。
咱們在控制檯打印一下.get()方法的返回值:
console.log(this.httpClient.get(`http://localhost:8080/Klass/${klass.id}`));
果真是一個對象,這個對象包含了訂閱數據源的功能,等到數據返回以後再使用.subscribe方法來操做返回的數據。
接下來,咱們來看subscribe方法:
subscribe(observer?: PartialObserver<T>): Subscription; /** @deprecated Use an observer instead of a complete callback */ subscribe(next: null | undefined, error: null | undefined, complete: () => void): Subscription; /** @deprecated Use an observer instead of an error callback */ subscribe(next: null | undefined, error: (error: any) => void, complete?: () => void): Subscription; /** @deprecated Use an observer instead of a complete callback */ subscribe(next: (value: T) => void, error: null | undefined, complete: () => void): Subscription; subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;
依然是選出一個,格式化成熟悉的形式:
能夠看出,這個方法須要傳入三個回調函數,分別爲:
因此只要把對應的方法傳入,就能夠了(也能夠不都傳入,subscribe因爲有重載函數,能夠處理不一樣的參數)。
在調用.subscribe時,爲何要傳入success和error兩個方法?
——實際上是爲了代碼解耦,回調函數的目的原本就是爲了代碼解耦。在方法A()中傳入方法B()用於回調,就能夠把方法A()執行以後的數據交給方法B()來操做。因此方法A()執行後的數據是不變的,具體怎麼操做這個數據,就要看傳進去的方法了。
同理,觀察者向數據源發起訂閱以後,當數據源發生變化時,把新的數據通知給訂閱者。數據既然已經拿到手,怎麼處理數據就是訂閱者的事了,和數據源不要緊了。因此在觀察者模式裏使用回調函數的好處在於:當處理返回值的功能發生變化時,並不用改動數據源的任何代碼。
這就比如:雜誌社把雜誌交給客戶以後,客戶想不想看、何時看,或者想把雜誌扔掉,都是客戶本身的事情,和雜誌社沒有半毛錢的關係。
數據源 + 訂閱者 = 觀察者模式
觀察者模式,是設計模式裏面最簡單的,也是最好理解的一種。
筆者也處於初學階段,之後會學到更多的設計模式。對於學習的過程來講,最大的喜悅,無非就是那種豁然開朗的感受了,從一開始的一團漿糊到後來的融會貫通。這種喜悅,應該就是學習最大的回報吧。