跳转到内容

计算机编程/基于组件的软件开发

来自维基教科书,开放世界中的开放书籍

软件工程学士学位

所有书架 > 科学 > 计算机科学 > 计算机编程 > 基于组件的软件开发

面向组件的编程

[编辑 | 编辑源代码]

软件组件目前是软件工程界最流行的术语之一。本章概述了组件技术、其重用概念和特性。然后,我们将简要概述软件架构及其与基于组件的开发的关系。最后,我们将以 JavaBeans 为例,考察组件模型。

软件危机

[编辑 | 编辑源代码]

1968 年,在加米施-帕滕基兴的北约会议上,首次提到了“软件危机”。人们承认软件开发很困难,甚至困难到必须被视为一项独立的工程学科。同时,人们也抱有希望,认为从困境中走出来的途径可能是形成一个新的软件组件产业和组件市场。

软件开发的现状与 19 世纪初的许多行业类似:产品是手工制作的,昂贵且容易出错。成熟行业的特征是,它制造的产品是由许多小型标准化且可互换的部件组装而成的。

例如,电子工程领域,像二极管、电阻器和晶体管这样的小型电子元件并非为单一应用而设计,而是为许多不同的应用而设计。它们可以在电路板上组合成更大的集成电路 (IC)。一个单一零件可以简单地用其他零件替换,只要它提供相同的功能。ISO、ANSI 或 DIN 等标准保证了组件的兼容性和可互换性。

组件的特征

[编辑 | 编辑源代码]

软件开发试图模仿这些重用机制。其理念是通过以“即插即用”的方式组装一套独立开发的“现成”(COTS)组件来开发软件系统。

“软件组件”的概念已经相当古老,但近年来它已经发生了很大变化。在早期的编程时代,软件组件主要被视为源代码模块,比如 FORTRAN 库,而现在对组件的要求更多了。关于软件组件到底是什么,没有普遍认可的定义。问题在于,观点很大程度上取决于作者的背景,而且近年来关于组件的讨论非常多,以至于组件的概念变得有些模糊不清。

然而,人们通常将一些通用属性与软件组件联系起来。一个很好的起点是 ECOOP 96 大会上提出的定义:

'"软件组件是具有合同指定接口和显式上下文依赖关系的组合单元。软件组件可以独立部署,并且可以由第三方进行组合。"'Clemens Szyperski,《组件软件》,ACM 出版社/艾迪生-韦斯利出版社,英国,(1998 年)。

接下来,我们将更详细地描述定义中出现的不熟悉的术语。

组件特性

[编辑 | 编辑源代码]

信息隐藏

[编辑 | 编辑源代码]

可能最重要的特征是,组件完全隐藏了它们的实现。Parnas 的信息隐藏原则早在很早的时候就强调了这一点。

“每个模块都隐藏了一个重要的设计决策及其实现,隐藏在明确定义的接口后面,当设计决策或实现发生变化时,该接口不会发生变化”。

组件就像黑盒子:程序员知道盒子外是什么样子,以及组件能提供什么,但他不知道组件内部是如何工作的。乍一看,这种完全封装似乎是一种限制,但我们会看到它实际上是一种帮助。

应用程序构建者从中获益,因为他可以用另一个组件替换该组件,只要它支持相同的接口和功能。此外,他不需要了解组件的内部工作原理,只需要了解组件的接口。

另一方面,组件提供者可以改变组件的实现,只要接口仍然满足。接口是 CBSD 中一个非常重要的术语。它被定义为“表示一个功能的命名方法集合”。接口充当组件提供者和组件用户之间的一种契约。它不仅应该说明组件的服务,还应该说明它对其环境的依赖关系。

没有源代码会带来一些需要解决的困难。首先,仍然必须能够将组件调整到用户的特定需求。在不知道组件实现的情况下进行调整被称为定制。此外,组件必须提供一个机制来获取关于其规范的信息。这种自描述性是通过内省来实现的。

上下文无关性

[编辑 | 编辑源代码]

组件可以轻松地转移到不同的应用程序环境中。因此,组件需要是自包含的软件元素,独立于任何其他组件。这种独立性是如此严格,以至于甚至不允许实现继承,因为实现继承会使组件依赖于它的超类,而改变超类会导致组件崩溃。接口继承只是一种对特征规范的简单概括,是允许的。

隐式调用。

[编辑 | 编辑源代码]

为了使组件可交换,组件最好不要直接相互寻址,而是通过间接机制。一个中央注册表存储所有关于组件和接口的信息。每次客户端想要调用一个方法时,它都会查询注册表以获取所需的接口,该接口反过来会返回一个对实现该接口的组件的引用。

组件模型

[编辑 | 编辑源代码]

对组件的下一个要求是它们是可互操作的,这意味着它们必须具有与用另一种编程语言编写或位于不同主机的组件进行通信的能力。此外,它们本身也必须能够转移到其他操作系统和硬件平台上。这些要求是通过虚拟机、交叉编译器和中间件来保证的,比如来自 Sybase 的Avaki EII、来自 OMG 的 CORBA 和来自微软的 DCOM。

组件不是孤立地使用,而是根据软件架构使用,软件架构决定了组件可以具有的接口以及组件如何组合。组件模型提供了一个组件之间交互的通用框架。组件模型是必须遵循的编程指南,以便可以使用组件。在框架之外,组件是不可用的。两个重要的组件模型是来自 Sun Microsystems 的 JavaBeans 和来自微软的 ActiveX,后者基于组件对象模型 (COM)。CBSD 的关注和成功主要归功于这两个组件模型。但是,现有的组件模型都没有实现人们对组件的所有期望的功能。

CBSD 的影响

[编辑 | 编辑源代码]

如果有一天 CBSD 真正大规模建立起来,它将从根本上改变软件的开发方式。通过组件化开发,编程组件的过程与将组件组合成应用程序的过程分离。希望组件能像乐高积木一样轻松地拼装在一起,而无需编写源代码。因此,即使是技术技能较少的领域专家也能组装应用程序。

此外,CBD 预计将对软件开发的质量产生重大影响。

  • 由于简单性,软件开发速度加快。无需从头开始开发一切,因为可以购买第三方组件。开发时间缩短,从而降低了成本。
  • 组件增强了软件的可靠性,因为它们经过多年的改进、测试和调试。除此之外,组合者可以选择和组合来自不同供应商的最佳组件。
  • 软件系统的可扩展性和可演化性得到了提高,因为组件可以灵活地被满足要求的另一个组件替换。

几年前,这种前景在软件开发界引起了狂热,因为人们期待组件能解决很多问题。现在,一些幻灭正在蔓延。CBSD 变得非常困难,因为软件由许多紧密耦合的相互作用实体组成,这些实体不能以直接的方式连接在一起。

与面向对象编程的区别

[编辑 | 编辑源代码]

通常,组件和对象会被混淆或混在一起。组件化开发确实借鉴了面向对象方法的许多概念。如今,组件化开发建立在 OOP 基础上,但比面向对象方法提供了更抽象的软件系统视图。

主要区别在于组件是完全封装的,正如我们刚刚看到的。组件严格禁止访问其内部,而在 OOP 中,需要了解对象的内部工作机制,例如从类继承时。这种 OOP 中的重用机制也称为白盒重用,因为源代码对洞察和修改是开放的。

此外,构建块的粒度也不同:组件存在于不同的尺寸,从库中的单个对象到整个应用程序。但在大多数情况下,组件是更大的实体,包含多个对象。

组合模式和软件架构

[编辑 | 编辑源代码]

OOP 的一个难点是交互协议的表示。在面向对象编程中,全局控制流分布在多个对象上。因此,对交互协议的修改会导致多个对象的更改,这阻碍了系统的直接演化。另一个问题是,对象只能在具有相似交互模式的系统中重用。

组件技术允许将软件系统的架构表示为可重用的实体。架构描述语言 (ADL) 使用抽象角色之间的协作来描述软件系统。角色是实际存在组件的一种占位符。在组合时,这些角色通过单独的连接器用组件填充。

好处是

  • 组件包含较少的上下文依赖关系,因此更容易转移到其他软件系统。
  • 交互协议可以重用。
  • 软件架构促进为系统创建精心设计的结构,而不是黑客将组件拼凑在一起。良好的结构提高了软件系统的可维护性,以便以后更容易进行更改。

JavaBeans 组件模型

[编辑 | 编辑源代码]

JavaBeans 是主流的 Java 组件模型,由 Sun Microsystems 于 1996 年推出。它考虑了构成组件的最重要特性。JavaBeans 定义如下

"JavaBean 是一个可重用的软件组件,可以在构建工具中进行可视化操作。"

Sun 与组件模型一起发布了一个简单的可视化组合工具,即 BeanBox。它更适合于用 Bean 进行实验,而不是提供专业的 IDE。对于实际应用,最好使用 Visual Age 或 JBuilder 等支持 JavaBeans 可视化组合的 Java IDE 之一。

正如我们所见,JavaBeans 与标准 Java 类没有太大区别。这使得 Bean 组件模型非常易于使用。但 JavaBeans 可能拥有一些大多数普通 Java 类不具备的功能

  • 持久性
  • 属性
  • 内省
  • 事件通信
  • 自定义

持久性

[编辑 | 编辑源代码]

一个对象成为 Bean 的要求是定义一个公共无参数构造函数,以便构建工具可以以简单的方式实例化 Bean(在 Point Bean 中,无参数构造函数是隐式给出的)。其次,需要实现java.io.Serializablejava.io.Externalizable接口之一。这些接口没有规定任何方法的实现,而是表示 Bean 可以保存在持久存储中,例如在文件或数据库中。这样,应用程序关闭或跨网络传输后,可以恢复 Bean。在持久存储中存储组件状态的能力称为持久性。Java 提供了标准的序列化机制,这使得序列化对象变得非常容易。或者,组件可以通过实现Externalizable接口以自定义方式存储(例如,以 xml 格式)。

Bean 的属性是所有可通过公共方法访问和修改的字段。这些 getter 和 setter 方法应该按照一定的命名方案标记为相应方法。

<PropertyName>(PropertyType).

另一方面,访问器方法由以下模式编程

public PropertyType get<PropertyName>()

这种命名约定背后的意图是,它帮助构建工具找出 Bean 的工作原理以及它的功能。正如我们所见,组件必须提供有关其服务的信息,这称为内省。JavaBeans 提供了两种内省机制:反射和BeanInfo类。BeanInfos 提供了有关 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 编程语言,而组件的重要目标是实现语言的独立性。

华夏公益教科书