以前在设计DirectUI界面库(该界面库现已开源, 可到 这里 下载)架构时,遇到一个接口继承相关的问题,当时没有太好的解决方案,却一直个耿耿于怀, 现在重新思考整理下。

我们的DirectUI控件层次大概如下: 

其中, 类名以 I 开头的都是接口:
IObject表示框架的基本接口, 要求实现类似COM里IUnknown的功能,
IControl表示控件的基本接口, 所有控件都从该接口继承,
IControlContainer表示容器类控件的基本接口,
IButton表示Button类的基本接口,
IPanel表示某种容器控件接口。
 
当然上面的框架是简化的情况,实际情况比上面的复杂的多, 但该图已经可以帮我们说明这里的情况。

在真正实现Panel和Button时,我们会发现大量的代码是重复和可以共用的,因此在实际实现时, 我们的框架可能会变成这样:

也就是说我们会出现接口和实现交叉继承的情况,实际上我自己在实现时就是用这种方法的, 我想大部分人都会用这种方法(实际上WPF也是用这种方法的)。
这种方法的缺点是显而易见的, 接口中包含了实现,基本上让接口失去了它应有的作用, 这在组件式编程中是致命的,比如本来在C++中我可以封装成DLL,然后以类似COM的方式暴露接口给外部, 现在用这种方式却没法做到了(只能用导出类的方式)。

那么我们怎样才能既基于接口编程, 又能在实现时实现代码重用呢? 这个东西实际上是个语法糖, 即如何既符合C++语法又能实现我们这个需求。

于是,我们想到了如下的实现方式: 

我们的这种实现方式基于C++模板, 总的来说就是把我们要实现的接口通过模板参数传到继承类体系的最底层, 该方式的代码大概如下:

class IObject
{
};

class IControl: public IObject
{
};

class IButton: public IControl 
{
};

template<typename TBase>
class CObjectImpl: public TBase
{
};

template<typename TBase>
class CControlImpl: public TBase
{
};

template<typename T, typename TBase>
class CButtonImpl: public TBase
{
};

class CButton: public CButtonImpl<CButton, IButton>
{
};

该方式基本上完全满足我们上面的需求,既实现了代码重用,又是基于接口编程,但是你有没有发现它有一个致命的缺点, 这个缺点就是C++模板导致的代码膨胀, 我们在 C++模板会使代码膨胀吗 对模板导致的代码膨胀有相关分析。也就是说我们上面的设计会导致每种控件继承类都有一份重复的代码, 即CControlImpl<IButton>和CControlImpl<IPanel>因为是不同的类实例, 因此它们会生成2分代码。你可能会觉得这个不算什么, 但是想想控件的继承类可能有好几十甚至上百,最终的可执行文件会被撑大不少。

那么有没有其他的方法来实现呢?  既能基于接口编程, 又能实现代码重用,还没有代码膨胀的问题。

于是,我们想到了下面这种实现方式:

这种方式是最原始的方式, 实际上就是把接口体系单独独立出来, 把实现体系也单独独立出来,  然后在最终类(Button和Panel)里继承组合起来。 当然这种方式也有缺点, 就是我们要多做些工作,因为我们要在最终类(Button)里实现接口(IButton), 在实现时我们要把所有接口需要实现的方法转发给实现类(CButtonImpl)。

最后,总结下上面三种方法:
第一种实现和接口混合继承的方法最简单,也最容易理解, 缺点是没法完全基于接口编程; 第二种基于模板的方法比较难理解,实现上也比较简单, 缺点是代码膨胀; 第三种多重继承的方法也比较容易理解, 缺点是我们要多做一些工作。

我暂时就想到这些方法, 不知道其他朋友对上面的问题一般是怎么解决的, 有什么好的解决方法?

转载于:https://www.cnblogs.com/weiym/archive/2013/02/08/2909387.html

接口继承中一个常见问题的思考相关推荐

  1. TypeScript基础入门 - 接口 - 继承接口

    转载地址 TypeScript基础入门 - 接口 - 继承接口 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.0.13 为 ...

  2. 读书笔记 effective c++ Item 34 区分接口继承和实现继承

    看上去最为简单的(public)继承的概念由两个单独部分组成:函数接口的继承和函数模板继承.这两种继承之间的区别同本书介绍部分讨论的函数声明和函数定义之间的区别完全对应. 1. 类函数的三种实现 作为 ...

  3. 什么叫虚继承(虚拟继承)?如何消除继承中的二义性?

    乍听虚继承,吓倒很多人!! 或许很多人会认为这和虚函数有关,其实,几乎没有任何关系.它的出现,是为了克服继承中一个非常棘手的问题,也就是臭名昭著的菱形继承(二义性)问题. 二义性,也就是说,假如我们有 ...

  4. [译]C#8.0中一个使接口更加灵活的新特性-默认接口实现

    9月份的时候,微软宣布正式发布C#8.0,作为.NET Core 3.0发行版的一部分.C#8.0的新特性之一就是默认接口实现.在本文中,我们将一起来聊聊默认接口实现. 众所周知,对现有应用程序的接口 ...

  5. C++中的接口继承和实现继承

    C++中的接口继承和实现继承 很多人认为,C++中是不存在接口继承的,只有Java.C#这类语言才提供了相应的语法支持. 但是,如同鲁迅说过的某句名言:世上本没有接口继承,用的人多了,才有了接口继承. ...

  6. java中如何定义接口_java中如何定义一个接口

    使用interface来定义一个接口.接口定义同类的定义类似,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成.定义接口的基本格式如下:[修饰符] interface 接口名 [e ...

  7. Java中接口继承接口

    今天在看线程池的源码的时候,观察到了一个之前没有关注的地方: 接口继承接口 举例如下: 线程池接口: public interface Executor {void execute(Runnable ...

  8. 什么是继承?Java中如何声明一个类继承另一个类?

    在现实生活中,说到继承,多会想到子女继承父辈的财产.事业等.在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关联体系.例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动 ...

  9. 设计一个接口, 并设计一个实现类实现该接口,演示它们的使用。具体,创建一个名称为Person的接口,在接口中定义两个方法sayHello()和sayBye()。

    设计一个接口, 并设计一个实现类实现该接口,演示它们的使用. 具体,创建一个名称为Person的接口,在接口中定义两个方法sayHello()和sayBye().然后,创建两个实现了Person接口的 ...

最新文章

  1. ​北京大学吴华君组诚聘医学/生信助理研究员和博士后
  2. android文字广告的循环滚动,android怎样写一个循环文字滚动的TextView
  3. opencv orb
  4. Android中广播接收者BroadcastReceiver详解
  5. 自包含 .NET Core应用程序
  6. 进程调度的时机,切换与过程,方式
  7. 数据结构排序系列详解之七 归并排序
  8. 澤天夬 (易經大意 韓長庚)
  9. 测试独立显卡坏,可以将显示器接口插在集成显卡上试试
  10. windows下qt程序报错“the inferior stopped because it triggered an exception”
  11. NPDP产品经理小知识:端到端的流程建设与跨职能团队管理
  12. python爬取拉钩python数据分析职位招聘信息
  13. 音视频开发之旅(36) -FFmpeg +OpenSL ES实现音频解码和播放
  14. 战神引擎独立端全套搭建教程
  15. 通过谷歌chrome我们可以进行视频通话
  16. 《熊猫人之谜》属性可能重大改变
  17. python使用tkinter库,封装操作excel为GUI程序
  18. 环境配置:前端程序员快速进行开发
  19. 我为何想参加2011年IT博客大赛?从心出发的选择
  20. java犀牛是什么意思_Java 8新特性探究(十二)Nashorn :新犀牛

热门文章

  1. ZOJ 3827 Information Entropy(数学题 牡丹江现场赛)
  2. 关于c++中运算符重载
  3. angularJs自定义模块
  4. 解决Button设置disabled后无法执行后台代码问题
  5. 简化软件产品的实际步骤
  6. asp.net常用函数 选择自 UAM_Richard 的 Blog
  7. python列表的append/entend/insert
  8. Relation(NOIP模拟赛)(二分图染色)
  9. 题目1208:10进制 VS 2进制(进制转换以及大数保存问题)
  10. 程序员,你也该为自己想想未来