计算机程序设计/基于组件的软件开发
软件工程学士
软件组件目前是软件工程界最流行的流行语之一。本章概述了组件技术、其重用概念和特性。然后,我们将简要概述软件架构及其与基于组件开发的关系。最后,我们将以 JavaBeans 为例来检查组件模型。
1968 年在加米施-帕滕基兴举行的北约会议上,首次提到了“软件危机”。人们承认软件开发很困难,甚至困难到必须将其视为一门独立的工程学科。此外,人们还希望摆脱困境的途径可能是形成新的软件组件产业和组件市场。
软件开发的状态与 19 世纪初的许多行业相似:产品是手工制作的,昂贵且容易出错。成熟行业的特征是它制造的产品由许多小型标准化和可互换的部件组装而成。
例如,电子工程,其中小型电子组件(如二极管、电阻器和晶体管)不是为单个应用而设计的,而是为众多不同的应用而设计的。它们可以组合在电路板上形成更大的集成电路 (IC)。只要提供相同的功能,单个部件就可以简单地替换为其他部件。ISO、ANSI 或 DIN 等标准保证了组件的兼容性和互换性。
软件开发试图模仿这些重用机制。其思想是通过以“即插即用”的方式组装一组独立开发的现成组件 (COTS) 来开发软件系统。
“软件组件”的概念已经相当古老,但在最近一段时间发生了很大的变化。在编程的早期,软件组件主要被视为源代码模块,如 FORTRAN 库,如今对组件有了更多要求。软件组件究竟是什么,没有统一的定义。问题是,观点在很大程度上取决于作者的背景,并且在过去几年里,关于组件的讨论很多,以至于组件的概念变得有些模糊和模棱两可。
然而,有一些通用属性,人们通常将其与软件组件相关联。一个好的起点是在 ECOOP 96 会议上做出的定义
“软件组件是具有契约指定的接口和仅显式上下文依赖性的组合单元。软件组件可以独立部署,并且可以由第三方进行组合。” Clemens Szyperski,组件软件,ACM 出版社/艾迪生-韦斯利,英国,(1998)。
接下来,我们将更详细地描述定义中出现的不熟悉术语。
可能最重要的特征是组件完全隐藏了它们的实现。Parnas 的信息隐藏原则早在很久以前就强调了这一点的重要性
“每个模块都隐藏了一个重要的设计决策及其实现,隐藏在一个定义明确的接口后面,当设计决策或实现发生变化时,该接口不会发生变化”
组件就像黑盒子:程序员知道外部是什么样子,以及组件可以提供什么,但他不知道组件内部是如何工作的。乍一看,这种完全封装似乎是一种限制,但我们会看到它实际上是一种帮助。
应用程序构建器从中受益,因为他可以将组件替换为另一个组件,如果它支持相同的接口和功能。此外,他不需要了解内部工作原理,而只需要了解组件的接口。
另一方面,组件提供者可以更改组件的实现,只要接口仍然满足即可。接口是 CBSD 中一个非常重要的术语。它被定义为“表示一项功能的命名方法集合”。接口充当组件提供者和组件用户之间的一种契约。它不仅应该提到组件的服务,还应该提到其对环境的依赖关系。
源代码的缺失带来了一些需要解决的困难。首先,仍然必须能够根据用户的个性化需求调整组件。在不知道组件实现的情况下进行适配称为定制化。此外,组件必须提供一种获取其规范信息的机制。这种自描述性是通过内省实现的。
组件可以轻松地传输到不同的应用程序上下文中。因此,组件需要是自包含的软件元素,独立于任何其他组件。这种独立性非常严格,甚至禁止实现继承,因为它使组件依赖于其超类,并且更改超类可能会破坏组件。接口继承,这仅仅是特性规范的概括,是允许的。
为了使组件可互换,理想情况下,组件不得直接相互寻址,而应通过间接机制。中央注册表存储有关组件和接口的所有信息。每次客户端想要调用方法时,它都会查询注册表以获取所需的接口,该接口又会返回对实现组件的引用。
对组件提出的下一个需求是它们必须是可互操作的,这意味着它们必须能够与用另一种编程语言编写的或位于不同主机上的组件进行通信。此外,它们本身也必须能够转移到其他操作系统和硬件平台。这些需求通过虚拟机、交叉编译器和中间件来保证,例如来自 Sybase 的Avaki EII、来自 OMG 的 CORBA 以及来自 Microsoft 的 DCOM。
组件不是孤立使用的,而是根据软件架构来使用,软件架构决定了组件可以具有的接口以及如何组合组件。组件模型提供了一个组件交互的通用框架。组件模型是必须遵循的编程指南,以便能够使用组件。在框架之外,组件是不可用的。两个重要的组件模型是来自 Sun Microsystems 的 JavaBeans 和来自 Microsoft 的 ActiveX,后者基于组件对象模型 (COM)。CSBD 的关注和成功主要归功于这两个组件模型。但是,现有的组件模型都没有实现对组件的所有期望功能。
如果有一天 CBSD 真的大规模建立起来,它将从根本上改变软件的开发方式。通过基于组件的开发,组件的编程过程与将组件组合成应用程序的过程分离。希望组件可以像乐高积木一样轻松地拼凑在一起,而无需编写源代码。因此,即使是技术技能较少的领域专家也可以组装应用程序。
此外,预计 CBD 将对软件开发的质量产生重大影响。
- 由于简单性,软件开发速度加快。无需从头开始开发所有内容,因为可以购买第三方组件。开发时间缩短导致成本降低。
- 组件增强了软件的可靠性,因为它们经过多年的改进、测试和调试。除此之外,组合器还可以选择和组合不同供应商的最佳组件。
- 软件系统的可扩展性和可演化性得到改善,因为组件可以灵活地被满足要求的另一个组件所替代。
几年前,这种前景在软件开发社区中引发了一种欣快感,因为人们期望组件能够解决很多问题。现在,一些幻灭感开始蔓延。CBSD 变得非常困难,因为软件由许多紧密耦合的交互实体组成,这些实体无法以简单的方式连接在一起。
通常,组件和对象会被混淆或混在一起。基于组件的开发确实从面向对象方法借鉴了许多概念。基于组件的开发,正如今天所理解的那样,建立在 OOP 的基础上,但比面向对象方法提供了更抽象的软件系统视图。
主要区别在于组件是完全封装的,正如我们刚刚看到的。组件严格禁止访问其内部,而在 OOP 中,需要了解对象的内部工作原理,例如从类继承时。OOP 中的这种重用机制也称为白盒重用,因为源代码对洞察和修改是开放的。
此外,构建块的粒度也不同:组件存在于不同的规模,从库中的单个对象到整个应用程序。但是,在大多数情况下,组件是更大的实体,包含多个对象。
OOP 的一个难点是交互协议的表示。在面向对象编程中,全局控制流分布在多个对象上。因此,对交互协议的修改会导致多个对象发生变化,这阻碍了系统的直接演化。另一个问题是,对象只能在具有相似交互模式的系统中重用。
组件技术允许将软件系统的架构表示为可重用的实体。架构描述语言 (ADL) 以抽象角色之间的协作来描述软件系统。角色是现有组件的一种占位符。在组合时,角色通过单独的连接器填充组件。
好处是
- 组件包含较少的上下文依赖关系,因此更容易转移到其他软件系统。
- 交互协议可以重用。
- 软件架构促进为系统创建精心设计的结构,而不是将组件拼凑在一起。良好的结构提高了软件系统的可维护性,以便以后可以更轻松地进行更改。
JavaBeans 是主流的 Java 组件模型,由 Sun Microsystems 于 1996 年推出。它考虑了构成组件的大多数重要特征。JavaBeans 定义如下:
"Java Bean 是一个可重用的软件组件,可以在构建工具中以可视方式进行操作。"
Sun 除了组件模型之外,还发布了一个简单的可视化组合工具 BeanBox。它更适合于实验 Bean,而不是提供专业的 IDE。对于实际应用,最好使用支持 JavaBeans 可视化组合的 Java IDE 之一,例如 Visual Age 或 JBuilder。
正如我们所看到的,JavaBeans 与标准 Java 类并没有太大区别。这使得 Bean 组件模型非常易于使用。但是 JavaBeans 可以具有一些大多数普通 Java 类不具备的功能。
- 持久性
- 属性
- 内省
- 事件通信
- 定制
要成为 Bean 的对象,需要定义一个公共的无参构造函数,以便构建工具能够以简单的方式实例化 Bean(在 Point Bean 中,无参构造函数是隐式给出的)。其次,需要实现java.io.Serializable或java.io.Externalizable接口之一。这些接口没有规定任何方法的实现,但表示 Bean 可以保存到持久存储中,例如文件或数据库中。这样做,可以在应用程序关闭或跨网络传输后恢复 Bean。在持久存储中存储组件状态的能力称为持久性。Java 提供了一种标准的序列化机制,这使得序列化对象变得非常容易。或者,可以通过实现Externalizable接口以自定义方式(例如 xml 格式)存储组件。
Bean 的属性是所有可以通过公共方法访问和修改的字段。这些 getter 和 setter 方法应该按照某种命名方案进行标记。
<PropertyName>(PropertyType).
另一方面,访问器方法由模式编程。
public PropertyType get<PropertyName>()
这种命名约定的用意在于,它可以帮助构建工具了解 Bean 的工作原理及其功能。正如我们所看到的,组件必须提供有关其服务的信息,这称为内省。JavaBeans 提供了两种内省机制:反射和BeanInfo类。BeanInfo 提供了有关 Bean 组件的复杂信息,但必须显式实现。
JavaBeans 通过事件相互交互。事件是组件可以向其他组件发出的通知,表示发生了某些有趣的事情。事件的一个示例可能是单击按钮或关闭窗口。Bean 可以是事件的源和目标。要收到事件通知,Bean 必须在另一个 Bean 上注册为监听器。
Java 事件模型实现了观察者设计模式,从而减少了组件间的耦合。方法调用需要紧耦合,因为调用方和接收方需要在编译时相互了解,而在事件中,所有通信仅通过接口进行。
有一种特殊的事件叫做PropertyChangeEvents。它们用于限制某些属性只能取特定的值,例如,对于月份,整数的值只能在 1 到 31 之间。每次修改这样的绑定属性时,都会向所有注册的PropertyChangeListeners发送通知。
定制是通过属性编辑器完成的。属性编辑器是用于在设计时定制特定属性类型的工具。属性编辑器从所谓的属性表激活,属性表显示 Bean 的所有属性。如果选择一个属性进行定制,属性表会找出该属性的类型,并显示相应的属性编辑器及其当前值。
JavaBeans 组件模型的一大优势在于它设计得非常简单。开发 JavaBeans 非常简单,因为许多行为(如平台独立性或打包机制)在 Java 编程语言中默认支持。但是,可以根据需要为 Bean 配备额外的对象,如BeanInfos 或自定义PropertyEditors,以便更灵活地使用组件模型。第二个特性是 Sun 根据 JavaBeans 组件模型设计了整个 Swing GUI 库。因此,Swing 组件可以轻松地在可视化构建工具中组合。
然而,JavaBeans 并没有实现组件模型的所有功能。一个缺点是 JavaBeans 受限于 Java 编程语言,而组件的一个重要目标是实现语言的独立性。