通過例子學設計模式之--介面卡模式以及使用場景說明(C++實現)
阿新 • • 發佈:2018-12-30
介面卡模式的定義:介面卡模式將一個類的介面轉換成客戶期望的另一個介面,讓原本不相容的介面可以合作無間。
該模式應該好理解。比如電源介面卡(中國和歐洲分別是電源220V,110V)就是該模式的一種表現。關於類圖或者其他說明我這邊就不囉嗦了。很多開發者包括我自己也是,更多困惑是不知道在實際的專案中該如何使用設計模式。本文希望通過例子來說明什麼情況下使用介面卡模式,算是拋磚引玉吧。
使用場景:我們準備開發一個新模組或者功能。現在的情況是我們已經有現成可用的模組或者第三方庫,這些模組經過客戶測試是完全符合需求的,而且是穩定的。當然大家都希望直接呼叫這些模組,而不是費時費力的從頭開發。問題是通過分析現有模組的介面或者第三方庫的時候,發現直接呼叫比較麻煩或者不符合現在的程式設計模式。比如資料結構的定義不一致,比如返回值不一致,比如介面引數不一致(很多時候第三方庫考慮各種相容性,而我們其實不一定需要)。
怎麼辦呢?好辦,增加一個"中間層"解決。這個中間層就是"介面卡模式"。如果不增加這個"中間層",或多或少會打亂我們現有的介面定義或者編碼方式。
實現方式: 一般是通過類介面卡或者是通過物件介面卡。如何區分這2種呢?類介面卡是通過"多繼承",即繼承的方式實現,耦合性很高,父類變化了子類就需要重新編譯連結,而且"多繼承"容易產生二義性,不建議使用。物件介面卡是通過物件組合"的方式實現,耦合性低,通常使用該方式。符合面向物件設計的一個基本原則"優先使用組合,而不是繼承"。
OK,最後還是通過例子來說明吧:
該模式應該好理解。比如電源介面卡(中國和歐洲分別是電源220V,110V)就是該模式的一種表現。關於類圖或者其他說明我這邊就不囉嗦了。很多開發者包括我自己也是,更多困惑是不知道在實際的專案中該如何使用設計模式。本文希望通過例子來說明什麼情況下使用介面卡模式,算是拋磚引玉吧。
使用場景:我們準備開發一個新模組或者功能。現在的情況是我們已經有現成可用的模組或者第三方庫,這些模組經過客戶測試是完全符合需求的,而且是穩定的。當然大家都希望直接呼叫這些模組,而不是費時費力的從頭開發。問題是通過分析現有模組的介面或者第三方庫的時候,發現直接呼叫比較麻煩或者不符合現在的程式設計模式。比如資料結構的定義不一致,比如返回值不一致,比如介面引數不一致(很多時候第三方庫考慮各種相容性,而我們其實不一定需要)。
怎麼辦呢?好辦,增加一個"中間層"解決。這個中間層就是"介面卡模式"。如果不增加這個"中間層",或多或少會打亂我們現有的介面定義或者編碼方式。
實現方式:
OK,最後還是通過例子來說明吧:
/* 被適配者,Adaptee */ class API3rd { public: int fun1(int param1,int param2,float f1,float f2) { printf("API3rd::fun1\r\n"); return 1; } float fun2() { printf("API3rd::fun2\r\n"); return 0.1; } }; /* Target類 */ class MyClass { public: MyClass(){}; virtual ~MyClass(){} virtual int f1(int param1) { printf("MyClass::f1\r\n"); return 0; } virtual int f2() { printf("MyClass::f2\r\n"); return 0; } }; /* 類介面卡,使用多繼承 */ class Adapter1 : private API3rd,private MyClass { public: virtual int f1(int param1) { printf("Adapter1::f1\r\n"); printf("由於API提供的介面引數太多,我們只需要關注一個引數即可。因此使用介面卡模式對該介面適配。\r\n"); return API3rd::fun1(param1,0,0.0,0.0); } virtual int f2() { printf("Adapter1::f2\r\n"); printf("由於API提供的介面的返回值不符合我們的需要,因此使用介面卡模式對該介面進行適配\r\n"); float f = API3rd::fun2(); return (f+0.5); } }; /* 物件介面卡,使用物件組合的方式代替繼承 */ class Adapter2 : private MyClass { public: Adapter2() { m_api = new API3rd(); } ~Adapter2() { if(m_api) { delete m_api; } } virtual int f1(int param1) { printf("Adapter2::f1\r\n"); printf("由於API提供的介面引數太多,我們只需要關注一個引數即可。因此使用介面卡模式對該介面適配。\r\n"); return m_api->fun1(param1,0,0.0,0.0); } virtual int f2() { printf("Adapter2::f2\r\n"); printf("由於API提供的介面的返回值不符合我們的需要,因此使用介面卡模式對該介面進行適配\r\n"); float f = m_api->fun2(); return (f+0.5); } private: API3rd* m_api; }; /* Client 呼叫場景 */ void TestAdapter() { Adapter1* ap1 = new Adapter1; ap1->f1(2); ap1->f2(); Adapter2* ap2 = new Adapter2; ap2->f1(2); ap2->f2(); delete ap1; delete ap2; }