BOS的设计缘由

原创 2007年09月28日 16:03:00
 
让自己的工作得到复用,是每一个开发者,尤其是身处设计层次的有经验的开发者的共同心愿。本文就从复用性入手展开讨论,引申出BOS的设计缘由。
 
1.1  问题
观察下述代码(C#),试着找出其复用性不佳之处:
 
interface Shape {…}
class Rectangle : Shape{…}
class Circle : Shape {…}
class Device {…}
 
class Program
{
       static void Main(string[] args)
       {
              Rectangle rect = new Rectangle();
              rect.width_ = 100;
              rect.height_ = 100;
             
              Circle circle = new Circle();
              circle.r_ = 50;
 
              Device dev = new Device();
              dev.Draw( rect );
              dev.Draw( circle );
}
}
 
代码1-1
 
 
作为一个开发者,你一定还对上次别人(或者你自己)复用你的某个方法、类或者框架的情景记忆犹新。这绝对是一件充满成就感并让你体验到什么是价值的事情。但是,由于各种原因,我们并不是每天都能体验到类似的成就感。在很多情况下,我们仍然在撰写复用性并不是那么良好的代码。例如,在上面这段几乎再熟悉不过的简单程序中,隐藏着不止一处损害复用性的细节。下面列出了这些细节:
1)  如果Rectangle类的代码有所变动,那么它和Program类需要重编译(即使Rectangle类和Program类不在同一个文件中)。
2)  如果Circle类的代码有所变动,那么它和Program类需要重编译。
3)  如果Device类的代码有所变动,那么它和Program类需要重编译。
4)  如果初始化配置参数有所变动(例如,圆的半径修改为100),那么Program类需要重编译。
 
初学者对重编译并不引以为然。但是有经验的开发者知道,重编译的代价绝不仅仅是一些CPU的计算时间。在有多人参与的实际项目中,你几乎总是能遇到重编译带来的问题:上下文代码的改变、编译选项不匹配、链接冲突、甚至是因粗心(这在多次改动代码时很常见)而错误删除或改动了部分语句,都会带来意料之外的忙乱和感叹:“这段代码在我的机器上原本是好好的!”
 
1.2  组件是解决方案
为了解决这个问题,我们创造了组件这一伟大的发明。虽然没有明确定义,但组件的全部秘密就在于它避免了重编译。如果一段代码原本可以工作,那么将其封装为组件就可以确保不发生粗心或链接错误。这是因为,组件是以编译后的二进制码存在,而不再涉及源代码。虽然组件仍然会遭遇外部问题(外部引用文件的缺失或系统环境设置不匹配),但它真真切切地避免了“内部”的烦恼。
 
回过头来观察代码1-1,则我们可以确信,将其中三个类—Rectangle、Circle、Device—封装为组件将大大提高复用性。如此一来,问题列表中的1至3可以得到有效解决:Rectangle、Circle或是Device的改动将只局限于自身,而不会传播到Program。这将使整个工程呈现出一种有利于分工、调试以及功能升级的优良结构。
 
具体的做法有很多,你可以使用COM、CORBA等等。无论哪种做法,例程1-1都必然经历与下列代码类似的变动:
 
class Program
{
       static void Main(string[] args)
       {
              Rectangle rect = CreateComponent( component identifier for Rectangle);
              …
              Circle circle = CreateComponent( component identifier for Circle);
              …
              Device dev = CreateComponent( component identifier for Device);
              …
}    
}
代码1-2
 
 
其中,CreateComponent起到了将组件从客户代码分离出去的关键性作用,同时它也是组件系统与客户代码联系的枢纽。CreateComponent的内部实现视你采用何种组件系统而定,但可以肯定的是,它会读取某个动态链接库来获得组件实例—只有通过动态链接库,组件才能成为可复用的二进制代码块。
 
与此相伴的另一个变化是,原有类在成为组件的过程中演变成了两个不同但具备某种联系的类。以Rectangle为例,客户代码中的Rectangle与动态连接库的中Rectangle必须是两个类,这才有可能实现客户代码和组件独立编译。同时,动态链接库中的Rectangle还必须能够转型为客户代码中的Rectangle,否则两者无法协同工作。不用多说,继承关系可以很好的满足这样的需求。即,动态链接库中的Rectangle应是客户代码中的Rectangle的派生类。如下图所示:
 

 
图1-1 接口/实现分离的组件结构
 
 
这样的结构通常被称为接口/实现分离。接口类通常是只含有纯虚函数(方法)的抽象基类(在C#、Java这些语言中,直接就设置了interface关键字用以指明接口类)。实现类则以具体的代码来实现接口类中确立的多个虚函数。我们在后文还将更多地讲述接口/实现分离结构的好处。通常来讲,组件需要采取这样的结构。
 
说到这里,必须指出目前实际上存在两类组件系统:其中的一类符合接口/实现分离的结构,另一类却并没有这样的强制要求。后一类组件的存在是由于Java和.NET Framework这些新型语言平台引入了从二进制代码块中动态读取类型信息的技术Reflection。这种技术的出现使得客户代码可以不借助接口类而是根据字符串使用动态链接库中的实现类。JavaBean便是这样的组件系统。但是,使用字符串而不是接口类不仅使用上不方便,也不具备型别安全性。事实上,这类组件系统更注重的是单个实现本身的复用(可以称为实现复用),而不能很好地支持相同接口的多个不同实现的切换(这可以称为接口复用)。而基于接口/实现结构的组件系统则对两者都可以很好地支持。BOS和我们以后的讨论都是针对接口/实现结构类型的组件。
 
使用组件之后,我们可以有效地解决问题列表中的1至3。但是,如果将想像稍作深入,我们会发现事情还能做得更好。 待续
本文为BOS(Basic Object System)相关文档。BOS是一个通用软件框架。BOS源码可在下面链接下载:
http://sourceforge.net/projects/bos-code

相关文章推荐

BOS V6.2开发指南_Web设计器

  • 2014年03月13日 09:40
  • 1.53MB
  • 下载

记互助网成立互有会的美丽缘由——人生的意义:平凡人要做点不平凡的事情

【1】人生的意义:平凡人要做点不平凡的事情 去过婺源的人都知道,婺源有一座特别的桥,叫做彩虹桥,这是中国最美的廊桥。 很多人知道这个桥,却不知道这座廊桥是由两个异想天开的年轻人建造的。 ...

分析百映社区的创建缘由

有人质疑百映社区方向不明确,这点绝对错误,从建站开始就已经明确,而且构思非常清楚。或许很多朋友认为百映缺点多,其实,百映作为一个综合性社区来说,不管是宣传、维护、管理等等都比专业社区要难的多,因为综合...

学习laravel框架缘由

对前途也很迷茫,目前在太原,现在的公司,一周6天班,而且1年后才有5险,上了也就是最低的标准,没办法,从北京回到这种二线城市,难免有很大差距,自己也是提前有了心里准备。但是,没想到的是,比北京的工作还...

一个网站的诞生01--缘由

大概在半年前,我觉得需要做一个网站,寻找新奇有趣的餐厅。 喜欢美食的人,在中意餐厅吃久了,总想找新餐厅换换口味,试试新菜和新的食材。 寻找新餐厅并不容易,甚至是艰难。由于众所周知的原因,网上流...

在启动web项目的时候出现java.lang.NoSuchFieldError: TRACE的缘由

首先下你看一下这个异常:NoSuchFieldError 提示的是与项目的log版本发生冲突 我的项目用的是log1.2.8  解决方案是换掉这个版本就可以了我换过之后的是1.2.15 严重: ...

CProgressCtrl::SetBarColor无效的缘由

CProgressCtrl::SetBarColor无效的缘由,苦心找了好久才发现……
  • npu_wy
  • npu_wy
  • 2014年06月12日 10:50
  • 951

内核模式驱动不推荐使用C++的缘由

本文所讲内容主要源自Windows DDK文档。 一、内存页面交换 和用户模式程序不同,内存页面交换对内核模式的代码不是透明的,而是需要一定程度的主动管理,要保证在代码执行过程中不会需要载入新...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:BOS的设计缘由
举报原因:
原因补充:

(最多只允许输入30个字)