1. 程式人生 > >關係密切的設計模式(二)

關係密切的設計模式(二)

策略模式 + 橋接模式

假設一個場景(需求),需要在一個分散式系統的每個元件裡,向基礎服務註冊自己。然而基礎服務要求各個元件根據元件自身不同的位置,其註冊策略也不同,如下表:

位置 註冊要求
位置一 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);
			...
	}
}