EMACS & 程序 编程点滴...
天下难事必作于易,天下大事必作于细
软件架构技术
TOP接口与实现分离
首先来看看【接口与实现分离】有什么好处:- 减少内存使用: 如果每次发布源代码,每一份程序都要有一份二进制代码,这浪费了内存空间。
- 避免DLL Hell问题: 解决不同dll版本引起的问题。
- 实现了简单的运行时多态: 基于同一接口类可能有不同的实现(不同的dll),用户可以选择使用,无须重新编译。
组件技术既是利用了接口与实现分离。在明确接口的基础上,实现出扩展性,维护性强大的组件架构设计。通过这样的实现, 将软件设计中的可变性最大限度地局部化,从而应对变化的软件需求。同时,作为公司的技术资产可以方便地再利用,扩展。
TOPC++中实现接口与实现分离的方法
用C++实现接口与实现分离很方便: 具体接口类用抽象基类定义,由其继承得到具体的实现类。再在实现类的dll中引入一全局C函 数,在其内部创建实现类的实例,再将其扔出去。最后,用户调用该C函数,得到实现类的实例。例如以下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/********** interface.h **********/ // 接口定义 #define interface struct interface IChap4_1 { virtual void FuncA(void) = 0; }; interface IChap4_2 { virtual void FuncB(void) = 0; }; // 创建组件对象实例 extern void CreateInstance(IChap4_1 **); extern void CreateInstance(IChap4_2 **); // 释放组件对象实例 extern void Release(IChap4_1 *); extern void Release(IChap4_2 *); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/********** component.cpp **********/ // 具体实现类 class Chap4 : public IChap4_1, public IChap4_2 { virtual void FuncA(void); virtual void FuncB(void); }; void Chap4::FuncA(void) { cout << "Chap4::FuncA~" << endl; } void Chap4::FuncB(void) { cout << "Chap4::FuncB~" << endl; } extern void CreateInstance(IChap4_1 **pIFace) { Chap4 *pChap4 = new Chap4; *pIFace = (IChap4_1 *)pChap4; cout << "CreateInstance IChap4_1~" << endl; } extern void CreateInstance(IChap4_2 **pIFace) { Chap4 *pChap4 = new Chap4; *pIFace = (IChap4_2 *)pChap4; cout << "CreateInstance IChap4_2~" << endl; } extern void Release(IChap4_1 *pIFace) { delete (Chap4 *)pIFace; cout << "Release IChap4_1~。" << endl; } extern void Release(IChap4_2 *pIFace) { delete (Chap4 *)pIFace; cout << "Release IChap4_2~。" << endl; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/********** client.cpp **********/ #include <objbase.h> #include <iostream.h> #include "interface.h" int main(void) { IChap4_1 *pChap4_1; CreateInstance(&pChap4_1); pChap4_1->FuncA(); Release(pChap4_1); IChap4_2 *pChap4_2; CreateInstance(&pChap4_2); pChap4_2->FuncB(); Release(pChap4_2); return 0; } |
微软的COM既是利用这样的技术,只是为了通用,定义了许多接口(函数)。比如为了控制对象实例的生存周期和多重继承下的接 口查询,定义了IUnknown接口。其中AddRef(),Release()用来维护对象实例的引用计数,QueryInterface用来查询接口。 又比如为了各种语言间共享接口定义,用IDL来定义接口。为了跨语言环境创建件对象,定义了IClassFactory。等等。
TOP组件对象技术
TOP接口定义准则
要在已有的组件上重新定义,修改接口是不可能的,只能定义新的接口,让已有组件多重继承新的接口。所以,最初组件设计的时 候就要考虑其功能性,扩充性,维护性。以下从软件的凝聚度和结合度两方面讨论这个问题。- 凝聚度(cohesion,モジュール強度) : 模块,组件内功能间关联性的强度。
包含了许多功能的模块,组件,或者函数,会使代码管理混乱。当用户的需求有所变化的时候,修改一处,影响的范围会变 得很大。所以说,凝聚度越高越好。凝聚度高的模块具有坚固性,信赖性,再利用性,易读性等特点。最好的情况下,一个功 能应对应一个模块(函数)。
- 结合度(coupling) : 模块,组件间有调用关系接口之间的连结强度。
结合度表征了模块独立性的强度。为了使模块更容易再利用,维护,模块间的结合度越低越好。
凝聚度和结合度就像是一个问题的两端。凝聚度高的模块,一般其结合度就低,而相反,凝聚度低的模块其结合度有很高。
一般按照下表来划分凝聚度的级别:
| 凝聚度 | 名称 | 特征 |
|---|---|---|
| 最强 | 功能凝聚 | 一个功能一个模块 |
| 强 | 连续凝聚 | 一个模块中虽然含有多个功能,但是分别单独被调用 |
| 协作凝聚 | ||
| 一般 | 顺序凝聚 | 将和某一数据相关的复数模块,按照顺序,组织成一个新的模块 |
| 临时凝聚 | ||
| 弱 | 逻辑凝聚 | 一个模块中执行多个处理 |
| 最弱 | 共存凝聚 | 毫不相干的功能为了实现某一机能而组织在一个模块中 |
结合度的级别:
| 结合度 | 名称 | 特征 |
|---|---|---|
| 最低 | 数据结合 | 将对方的模块作为黑盒,只是将必要的数据作为参数来传递 |
| 低 | 标记结合 | 对方模块即使只使用结构体内的部分数据,也将构造体整体作为参数传递给对方 |
| 一般 | 控制结合 | 将模块控制代码作为参数传递给对方,从而控制对方模块的行为。于逻辑凝聚同等级别。 |
| 高 | 外部结合 | 模块间共用全局变量,通过全局变量实现模块间交互 |
| 最高 | 内容结合 | 须参照其他模块内部的构造来处理 |
http://www.ogis-ri.co.jp/otc/hiroba/technical/Cohesion_Coupling/Cohesion_Coupling.html