關係密切的設計模式(二)
阿新 • • 發佈:2018-12-11
策略模式 + 橋接模式
假設一個場景(需求),需要在一個分散式系統的每個元件裡,向基礎服務註冊自己。然而基礎服務要求各個元件根據元件自身不同的位置,其註冊策略也不同,如下表:
位置 | 註冊要求 |
---|---|
位置一 | 1、計算並快取本地資料摘要值(需要提供查詢摘要介面);2、將摘要值通過介面註冊給基礎服務A |
位置二 | 1、計算並快取本地資料摘要值(需要提供查詢摘要介面);2、將摘要值通過介面註冊給基礎服務B |
位置三 | 1、計算並快取本地資料摘要值(需要提供查詢摘要介面);2、將摘要值通過介面註冊給基礎服務A;3、將摘要值通過介面註冊給基礎服務B |
位置四 | 1、計算並快取本地資料摘要值(需要提供查詢摘要介面); |
此情況下,很明確使用策略模式不僅會簡化問題、增強封裝性,還能在今後再出現“位置X”的時候,不需要修改老程式碼。但僅使用策略模式,四個位置的實現類中,會不同程度的出現重複程式碼。直接想到的解決方法是,將計算摘要和呼叫註冊介面寫成公共函式,放在基類中。
本文想提供另一個思路,此思路基於一個設計原則:“少用繼承,多用組合”。即使用橋接模式,重複用到的函式,不直接在基類中實現,而是再定義一個IMPL類實現這些功能,並將此類作為基類的一個成員。
enum BASE_SERVICE { SRV_A, SRV_B }; class CompImpl { public: CompImpl(const char* db_data, unsigned int data_len); void CalcDigest(){...} // 這裡假設摘要定長 bool RegDigest(BASE_SERVICE base_service){...} char* GetDigest(){...} private: char digest[DIG_LEN]; }; // 介面類 class IPosReg { public: IPosReg(const char* db_data, unsigned int data_len) : impl_(db_data, data_len){impl_.CalcDigest();} virtual ~IPosReg(){} virtual bool RegDigest() = 0; virtual char* GetDigest(); protected: CompImpl impl_; }; // 以下為實現四個位置的子類 class CPos1Reg : public IPosReg { public: CPos1Reg(const char* db_data, unsigned int data_len) : IPosReg(db_data, data_len){} virtual bool RegDigest(){return impl_.RegDigest(SRV_A);} vitrual char* GetDigest(){return impl_.GetDigest();} }; class CPos2Reg : public IPosReg { public: CPos2Reg(const char* db_data, unsigned int data_len) : IPosReg(db_data, data_len){} virtual bool RegDigest(){return impl_.RegDigest(SRV_B);} vitrual char* GetDigest(){return impl_.GetDigest();} }; class CPos3Reg : public IPosReg { public: CPos1Reg(const char* db_data, unsigned int data_len) : IPosReg(db_data, data_len){} virtual bool RegDigest(){ bool ret = impl_.RegDigest(SRV_A); if (!ret) return ret; return impl_RegDigest(SRV_B); } vitrual char* GetDigest(){return impl_.GetDigest();} }; class CPos4Reg : public IPosReg { public: CPos1Reg(const char* db_data, unsigned int data_len) : IPosReg(db_data, data_len){} virtual bool RegDigest(){return false;} vitrual char* GetDigest(){return impl_.GetDigest();} }; enum REG_POSITION{ REG_POS_1, REG_POS_2, REG_POS_3, REG_POS_4 }; IPosReg* CreatePosIns(REG_POSITION reg_pos, const char* db_data, unsigned int data_len){ switch (reg_pos) { case REG_POS_1: return new CPos1Reg(db_data, data_len); ... } }