策略模式 + 桥接模式
假设一个场景(需求),需要在一个分布式系统的每个组件里,向基础服务注册自己。然而基础服务要求各个组件根据组件自身不同的位置,其注册策略也不同,如下表:
位置 | 注册要求 |
---|---|
位置一 | 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);
...
}
}