乌托邦式的接口和实现分离技术
2008-02-23 05:35:27来源:互联网 阅读 ()
考虑这样一个接口设计:
struct IRefCount; struct IReader : public IRefCount; |
在Reader中实现接口:
<!--[if !supportEmptyParas]--> class Reader : public IReader;
在上述的继承结构中,IRefCount是个结构性的类,用来实现引用计数,实际上他和领域逻辑部分IReader没有什么关系。我们打算在IRefCount的基础上,建立了一套工具来管理对象生命周期和帮助实现异常安全的代码 (例如,smart pointer) 。现在来考虑Reader的实现,Reader除了需要实现IReader的接口,还必须实现IRefCount的接口。这一切看起来似乎顺理成章,让我们继续看下面的设计<!--[if !supportEmptyParas]-->:
struct IWriter : public IRefCount; <!--[if !supportEmptyParas]--> class Writer : public IWriter; |
现在来考虑Writer的实现,和Reader相同,Writer除了要实现IWriter的接口外,同时还需要实现IRefCount的接口。现在,我们来看看IRefCount是如何定义的:
struct IRefCount { virtual void add() = 0; virtual void release() = 0; virtual int count() const = 0; virtual void dispose() = 0; virtual ~IRefCount(){} }; |
在Reader中的IRefCount的实现:
virtual void add() { m_ref_count;} virtual void release() {--m_ref_count;} virtual int count() const{return m_ref_count;} virtual void dispose() { delete this;} … int m_ref_count; |
同样,在Writer的实现中,也包含了一模相同的代码,这违背了DRY原则(Don’t Repeat Yourself)。况且,随着系统中的类增加,大家都意识到,需要将这部分代码复用。一个能够工作的做法是把IRefCount的实现代码直接放到IRefCount中去实现,通过继承,派生类就不必再次实现IRefCount了。我们来看一下dispose的实现:
virtual void dispose() { delete this;} |
这里,采用了delete来销毁对象,这就意味着Reader必须在堆上分配,才可能透过IRefCount正确管理对象的生命周期,没关系,我们还能够override dispose方法,在Reader如下实现dispose:
virtual void dispose() { } |
但是,这样又带来一个问题,Reader不能被分配在堆上了!假如您够狠,当然,您也能够这么解决问题:
class HeapReader : IReader; class StackReader : HeapReader{ virtual void dispose() { } }; |
问题是,StackReader 是个HeapReader吗?为了代码复用,我们完全不管什么概念了。当然,假如您和我相同,看重维护概念,那么这么实现吧:
class HeapReader : IReader; class StackReader : IReader; |
这样一来,IReader的实现将被重复,又违背了DRY原则,等着被将来维护的工程师诅咒吧!或许,那个维护工程师就是3个月后的您自己。假如这样真的能够解决问题,那么也还是能够接受的,很快,我们有了一个新的接口:
struct IRWiter : IReader, IWriter; class RWiter : public IRWiter; |
考虑一下IRefCount的语义:他用来记录对所在对象的引用计数。很显然,我从IReader和IWriter中的任意一个分支获得的IRefCount应该都是获得相同的引用计数效果。但是现在,这个继承树存在两个IRefCount的实例,我们不得不在RWiter当中重新重载一遍。这样,从IReader和IWriter继承来的两个实例就作废了,而且,我们可能还浪费了8个字节。为了解决这个问题,我们还能够在另一条危险的道路上继续前进,那就是虚拟继承:
struct IReader : virtual public IRefCount; struct IWriter : virtual public IRefCount; |
还记得大师们给予的忠告吗--“不要在虚基类中存放数据成员”。“这样有什么问题吗,我们不必对大师盲目崇拜”,您一定也听过这样的建议。假如大师们不能说服这些人,那么我也不能。于是,我们进一步在任何的接口中提供默认实现,包括IReader和IWriter.
现在的问题是:
struct IRWiter : IReader, IWriter; |
还是
struct IRWiter : virtual IReader, virtual IWriter ? |
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇: C 还能重新辉煌吗?C 复杂性的思考
下一篇: 重载、覆盖和隐藏 之细谈
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash