分享
 
 
 

一种通用的接口设计方案

王朝other·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

1.1 背景

目前的XXXX扩展接口定义如下:

class ProductProcess

{

public:

virtual long process(const in_type&,out_type&) = 0;

…. //还有其他扩展接口也定义在一起

}

讨论集中在上面process成员函数的定义。因为产品需求的变化,目前的process函数需要在两种情况下调用,因此考虑两种修改方案:

1)修改process为:long (int flag,const in_type&,out_type&)

flag代表不同应用场合

2)定义不同名字的虚函数

3)修改process为long process(int flag,void* in_pData,void* out_pdata) = 0;这种方式意图是支持不同处理参数

我们都希望这次改动之后系统的可扩展性更好

1.3 分析首先说明,每种设计方案都有自己的优缺点,不存在一个最好的方案。只能依据软件设计的一些基本原则来分析一个设计是否有改善的余地,

1. 看接口类ProductProcess的定义,因为包含多种处理业务的扩展接口,这些扩展接口之间基本上没有关系,是松散耦合的,很显然违背了ISP(接口分离原则)。

2. long (int flag,const in_type&,out_type&)的定义,首先要求平台和产品在处理flag参数上保持一致,但只是口头或文档约定,无法避免实际代码中出现不一致的情况,造成平台和产品代码之间的紧耦合。另外针对各种业务处理流程都要求在同一个接口中实现,一旦某个业务接口发生变动,将对其他业务接口的实现造成影响,个人认为很明显违背OCP(开放封闭原则)

3. long process(int flag,void* in_pData,void* out_pdata)的定义,想实现任意扩展业务处理接口,而且对业务处理数据的类型不限制,但实际上也无法做到,因为某个业务处理接口可能有1个参数,也可能有多个参数,对于后者,还需要包装多个参数,使用不方便,关键是利用void*传递各种数据不是类型安全的,C++中应该慎用。

1.4 考虑

能够用一种更好的方式实现long process(int flag,void* in_pData,void* out_pdata)的设计意图,甚至增强其适应范围,即对参数个数和类型都不加限制。当然是用面向对象的思想方式,通过接口,继承等技术来实现。看起来肯定比单纯的一个成员函数复杂得多,但更灵活,甚至可以统一任意扩展接口的实现方式。

1.5 我的实现方式因为各个业务处理的参数类型,参数个数都是不同的,无法通过一个接口来定义所有的业务处理,考虑一个退化的接口类型的实现方式,如下:

ExpandInterface做为任何扩展接口的基类定义,只是提供一个类型表示,具体业务处理接口有其子接口定义, 二次开发人员的具体实现是这些子接口的子类。比如,上面分别为同步告警和接受实时告警定义了不同的子接口。这两个子接口从形式上看是一摸一样的,为什么不统一呢?我认为这里只是接口定义,重复代码可以忽略不计;他们的行为方式是不同的,定义不同的接口名非常容易理解,这样的代码可以说是自注释的;两种告警业务处理本来不相关,分开之后可以独立变化对另一个没有任何影响。从以上三方面考虑,分开定义更好。

另外,平台应该提供一个供二次开发人员设置其实现类的接口,提供这样一个扩展接口的管理类:

ExpandManager是平台提供的一个实现类,二次开发人员直接使用,它只能看到ExpandInterface接口。

对于平台开发人员来讲,就存在一个问题,它是怎么知道某个ExpandInterface是RealAlmInterface还是SynAlmInterface呢?因为ExpandManager,ExpandInterface, RealAlmInterface, SynAlmInterface都是平台定义并实现的,从技术上讲,平台开发人员可以利用dynamic_cast转换每个ExpandInterface进行尝试,最终找到自己需要的接口。

很遗憾,我们无法利用typeid来实现ExpandManager::add(ExpandInterface*):

void add(ExpandInterface* p){

_map[typeid(*p).name()] = p; //直接对一个指针类型使用typeid不能得到其真实的子类类型

}

我们无法通过typeid(*p)来获取中间层次(这里的RealAlmInterface,SynAlmInterface)的类型信息。

为了避免在平台内部频繁使用dynamic_cast,我们需要在ExpandInterface接口上增加能够判断子接口类型的功能,很容易想到的方法如下:

class ExpandInterface

{

public:

virtual int getProtocol() = 0;

};

class RealAlmInterface: public ExpandInterface

{

virtual int getProtocl() { return REAL_ALM_PROCESSOR; }

};

要求平台为定义的每个业务处理接口,也就是ExpandInterface的子类实现getProtocol纯虚接口,这样ExpandManager::add(ExpandInterface*)的实现就非常简单了:

void add(ExpandInterface* p){ _map[p->getProtocl()] = p; }

通过这种方式平台开发人员也很容易获取某个业务处理接口,新增业务处理接口只需要在平台定义的时候保证其业务标识是唯一的,不重复的即可,与二次开发也没有任何关系。

但是这种方法的确还存在一个比较大的缺点,无法避免二次开发人员也重载了getProtocl接口并返回不同的值,这种重载可能是恶意的,也可能是无意的。为了避免这种情况,我们需要提供文档解释说明二次开发人员不要重载这个接口,但无法保证实际代码中会发生什么。

我们需要一个ExpandInterface中定义的接口,平台可以使用,可以修改,产品无法使用也无法修改,visitor模式可以帮助我们做到这一点。

业务类型也就是每个ExpandInterface的子类的类型信息保存在Visitor类中。二次开发人员无法修改RealAlmInterface::accept接口的关键之处是平台不对外公布Visitor类的定义,只是在ExpandInterface的定义文件中使用Visitor类的前向声明即可,这样二次开发人员多能做的事情就是实现一个空的accept函数,这样,在平台实现代码的时候,调用accept之前赋予Visitor一个合理缺省值,能够检测到这种情况,给出拒绝或警告提示,总之一切又都在平台的控制之下。

1.6 完整类图

对外提供接口:

ExpandInterface, RealAlmInterface,SynAlmInterface

对外提供的实现体,直接使用:

ExpandManager

只对内提供的定义:

Visitor

二次开发需要实现的:

ConcretRealAlm, ConcretSynAlm

1.7 其他考虑有的业务允许多个扩展接口串行处理,这种方式的支持不建议在ExpandManager和ExpandInterface层面进行改动,而是将ExpandInterface的子类,即业务处理接口设计为职责链模式(chain of responsibility),同时结合模板方法(template method)即可:

这种通用接口的设计可以用于任何需要扩展处理的地方,平台和二次开发人员之间只需要通过不会产生任何歧义的接口进行交互,而且避免二次开发人员无意或恶意的错误

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有