Rational
Software Architect 如何将 SOA 开发自动化
学习如何扩展 IBM? Rational? Software Architect,并且利用您自己的最佳实践和资产,将面向服务的体系结构(service-oriented
architecture,SOA)解决方案的设计自动化。 Rational Software Architect
提供了一些当您在设计 SOA 和其他解决方案时,可以结合使用的、用来提高生产力的特性。您还可以利用这些自动化特性来提高解决方案质量,并且用来支持您整个的治理过程。
预备知识
学习本教程所讲内容,以及如何充分利用这些内容。
关于本系列
要获得模型驱动开发(model-driven development,MDD)的好处,您的设计及开发环境需要有以下特征:
用于复用的最佳实践:人们可以复用已证实的解决方案来解决重复重复出现的问题,并且这些解决方案能够被其他人复用。
基于角色的工具:工具是针对手边的任务的,并且是针对执行该任务的人的角色的(例如,业务分析员或 IT 架构师)。
过程支持与指导:上下文中总是存在方法或过程。
可扩展的平台:团队可以扩展或定制环境来适应他们的需要。
自动化:框架的底层元模型和映射允许模型从较高抽象层到较低抽象层,及最终到可执行代码的半自动转换。从较低抽象层追溯到较高抽象层也是可行的。
这些是 IBM Rational 软件交付平台所包含的特性,更具体的说是
IBM? Rational? Software Architect 所包含的特性。
当学习过该系列教程之后,您应该能够描述出 SOA 解决方案设计中您用来扩展 Rational Software
Architect 的特性。您将了解到什么是建模,以及如何创建 UML 概要文件、模型模板、模式、转换,及可复用资产。
关于本教程
在本教程,系列的第 1 部分中,我们将讨论 SOA 和 Rational Software Architect
的可扩展特性之间的关系。我们介绍了您可以如何利用 Rational Software Architect
中您自己的定制模板和概要文件,将 SOA 解决方案的设计自动化。Rational Software Architect
提供了许多在您设计 SOA 和其他解决方案时可以使用的提高生产力的特性。您还可以使用这些自动化特性来提高解决方案质量,并支持整个治理过程。
目标
当您完成了本教程之后,您将更好地了解到您可以如何利用 Rational Software Architect
中的工具和特性来构建您自己的模板和概要文件。您可以利用这些自动化特性来提高团队的生产力、提高解决方案的质量,并支持您的治理过程。这些自动化特性编入了您的最佳实践,它们往往是针对您的组织的,并且作为组织竞争优势的一部分。
当您完成了本教程时,您将能够描述在 Rational Software Architect 中创建模式的不同方法。此外,您将能够创建简单的概要文件和模板。
预备知识
为了从本教程中获得更多价值,熟悉以下这些方法和软件是有帮助的,但不是必要的:
UML,统一建模语言(Unified Modeling Language)
Rational Software Architect 或 IBM? Rational? Software
Modeler
SOA,面向服务的体系结构(service-oriented architecture)
参见本教成末尾的参考资源部分,查看关于这些主题的有用链接。
系统需求
为了完成本教程,您应该安装以下内容:
Rational Software Architect 或 Rational Software Modeler
面向服务体系结构的模型驱动开发介绍
在另一个标题为“Design SOA Services with Rational Software Architect”(参考资源中列出)的系列中,我们介绍了如何使用模型来获取
Rational 基于 SOA 的解决方案的设计。我们已经能够在许多不同的抽象层次上工作,并且以这种方式使用了许多模型元素。这些模型元素曾经帮助指导我们的设计,并且允许我们在需要时生成详细的工件。
在本教程中,您将学习到如何在 Rational Software Architect 中构建您自己的 MDD
建模工件,包括以下两部分:
概要文件:利用 UML 形式化的扩展机制,我们能够通过添加原型、属性和约束条件来定制语言。
模型模板:当在 Rational Software Architect 中创建新的模型时,模型模板是很有用的。与其从空白模型开始,倒不如构建一个拥有预定义的包含了模型元素、图和文档的结构的建模工程。您经常会为具体的任务定制模型模板,例如创建用例模型或分析模型。
以下几个部分更详细地介绍了这两个工件。您将了解到它们是什么,您如何构建它们,以及最重要的,您如何在创建
SOA 解决方案时使用它们。在我们深入到这些工件的细节之前,熟悉相关的术语是很重要的。
SOA 和模型、资产、模式,及可扩展性
图 1 展示了 SOA 解决方案层次,它是 SOA 解决方案在运行时的概念表示。它引入了五个层:
Consumers(客户)
Business Processes(业务过程)
Services(服务)
Service Components(服务组件)
Operational Systems(操作系统)
您可以将这些层映射到带有更高抽象层次上的更高层的软件工程规程,或抽象层次。SOA 解决方案层次的核心是服务层(图
1),它代表面向服务解决方案的软件架构。
图 1. SOA 解决方案层次
SOA 术语及概念
尽管人们对应用于 SOA 解决方案层次的服务组件层的 Gang of Four (GoF) 设计模式更熟悉,但是模式还可以应用于其他所有的
SOA 层。当把 SOA 作为架构风格时,可扩展性、资产复用,或自动化都会应用到所有五个层次上。例如,商业架构层模式,如
IBM ? Component Business Model 中所包含的那些模式,根据所提供和所需要的商业服务,将组织表示为实体。
模型驱动开发(Model-driven development,MDD),基于模型和转换,它能让您在不同的抽象层次上为软件建模,并且对可追溯性和可度量性建模。因此,依据
MDD 方法来交付 SOA 解决方案是有很大意义的。设想,例如,为 SOA 解决方案层次的五个层的每一层设立
SOA 解决方案的模型,并且能够将模型从较高抽象层转换为较低抽象层。SOA 模型和转换已经在许多项目中成功地创建和使用了。例如,它们包括
Unified Modeling Language (UML) Profile for Software
Services 和 UML to Web Services Definition Language (WSDL)
transformation。(参见“Design SOA Services with RSA”教程,见参考资源列表,了解这两个部分的更多详情。)在
SOA 的环境中使用 MDD 的好处包括一致性的改进,让所有不同的涉众都具有 SOA 的透视图、质量和生产力的获得,以及尽一切办法将决策追溯到商业需求。
复用是 SOA 项目成功的关键因素,而它是一件有挑战的事情。它包括专家经验和最佳实践的复用,以及现有(非
SOA)软件资产的复用。
基于资产的开发(Asset-based development,ABD)是基于利用软件资产来构建解决方案的软件工程规程。采用
ABD 方法来交付 SOA 解决方案会带来很多好处。然而,保证 ABD 的成功需要具备很多的条件,而它不仅是关于文化的变更。例如,您需要资产(认可的,反对的,等等)生命周期的过程,而企业中的人需要能够在实现
SOA 解决方案时,发现并使用它们。服务是一个关键的资产类型。
服务注册中心和存储库支持复用,因为在生命周期的各个阶段中,它们都保留着服务的信息。服务注册中心和存储库确保了您可以复用服务,并且确保服务是可用的。资产存储库,例如
Reusable Asset Specification (RAS) 存储库,也是重要的,因为它们存储了那些包含了在所有抽象层上的服务的表示的资产(例如,表示
SOA 系统架构的 Rational Service Architect Service Model)。
如何创建 UML 概要文件
UML 概要文件为独立于领域的统一建模语言(Unified Modeling Language,UML)提供了简单的扩展机制。它们可以定义具体领域的实体和规则。概要文件针对的领域可以是技术驱动的,或商业驱动的。UML
概要文件也与开发过程很好地结合起来了。例如,现有的支持 IBM? Rational Unified Process?(RUP?)for
Business Modeling 的 UML Profile for Business Modeling。概要文件提供了一种简单的元模型建模技术,您可以使用该技术通过利用原型(以定义元类的细节和约束条件)和标记值(以定义元属性的约束条件),由现有的元模型定制元类。
将图形表示与原型联系起来是最好不过的。例如,在 UML profile for Software Services
中,serviceSpecification 原型特指 Interface 元类。它定义了一个发布的属性,以指示服务规范是否已经向服务注册中心发布。最后,其中一个约束条件是所有操作都需要公开标记。通过使用概要文件,您可以定制您用于设计、编写文档和开发
SOA 解决方案的语言。
提示:
实际上,您可以使用 IBM? WebSphere? Business Modeler 来处理业务,以获取商业过程的所有方面。您可以在
Rational Software Architect 中的 WebSphere Business Modeler
中打开模型。在 Rational Software Architect 中,您可以将它们用作形成详细技术设计的转换的输入。
如我早先阐述的那样,模型驱动开发中的一个关键思想是它允许您工作于多个抽象层次上。例如,您可能发现在与 SOA
项目的业务合作伙伴讨论时,UML profile for Software Services 太偏技术化了。因而,创建一个新的概要文件,去掉软件服务概要文件中的一些细节可能会讲得通。当您在较高层次上的模型中获取的细节上达成一致时,您可以通过转换,利用
UML profile for Software Services,将较低层上的模型的创建自动化。
新建概要文件或元模型的最佳方法
值得注意的是概要文件不是最好的元模型扩展机制。例如,概要文件不能为元模型(例如 UML 元模型)删去或定义新的元类或关系,而且它不能去掉它定制的元模型所表现出的约束条件。最好的扩展机制是
Object Management Group (OMG) MetaObject Facility (MOF)
和 Eclipse Modeling Framework (EMF)。参见参考资源中的 OMG 网站的链接,了解更多关于
MOF 和 EMF 的信息。
关于概要文件的使用
概要文件有以下使用特征,如 UML 2.0 规范中所描述的:
概要文件可应用于现有的模型。在这种情况下,现有的模型元素是专用的,或受约束于概要文件所建模的领域。
概要文件可以从它们所应用的模型中删除掉。当删除时,来自概要文件的额外细节和约束条件将不再出现于模型中。然而,模型仍旧有效,因为概要文件没有破坏它们所应用于的元模型。
新的模型可以围绕具体的概要文件而创建,可能使用模板,根据概要文件进行裁减。使用模型模板的优势是它们通常提供一个适用于概要文件所建模的领域的包结构和构建块。
可以向模型应用一个以上的概要文件。
工具不需要通过打开应用于模型的概要文件来了解其内容。它们可以在不用了解概要文件的情况下打开模型。
在 Rational Software Architect 中创建您的 UML 概要文件
这部分只是创建概要文件的基本介绍,因为概要文件的创建可以作为一个完整的教程或系列的主题。此处,我们不着重于概要文件创建的最佳实践,也不创建完整的概要文件。相反,我们将向您介绍如何使用
Rational Software Architect 来创建概要文件。参见参考资源,了解关于处理概要文件的详细的
developerWorks 文章的链接。
提示:
教程这部分要注意的一件重要的事是,我们正在使用 Rational Software Architect,版本
7。参见参考资源中试用版本下载的链接。
注意:
当您创建概要文件时,您只在 Project Explorer 和 Properties 视图中工作。
确保您处于 Modeling 透视图中。
选择 File > New > Project,并在 New Project 向导的 Filter
字段中输入 profile
选择 UML Profile Project 并单击 Next(图 2)。
图 2. 新建 UML 概要文件工程
将工程命名为 SimpleServiceProfile
单击 Next 两次,然后输入 SimpleServiceProfile 作为 Profile Name
和 File Name(图 3)。
单击 Finish。
图 3. 输入 UML 概要文件和文件名
定义概要文件的原型
既然您已经创建了概要文件模型和工程,那么您将需要定义带有原型(概要文件模型的主要模型元素)的概要文件。
选择 SimpleServiceProfile > Profiles。
在 Project 视图下,选择 SimpleServiceProfile。
单击右键,并选择 Add UML > Stereotype(图 4)。
将原型命名为 SimpleServiceSpec。
图 4. 创建新的原型
现在,指定新创建的 SimpleServiceSpec 原型所继承的类型(元类).
在 Project Explorer 中,确保选择 SimpleServiceSpec 。
单击 Properties 视图的 Extensions 选项卡,然后单击 Add Extension。
在弹出的 Create metaclass extension 窗口的 Metaclass 字段中,输入
Interface。
确保选择了 Interface,并单击 OK。
通过这种方式,您将规定,SimpleServiceSpec 原型继承了名为 Interface 的 UML
元素。当您完成并部署了该接口时,概要文件的用户将能够创建表示 SimpleServiceSpec 的 Interface
的特殊实例。图 5 展示了结果。
图 5. SimpleServiceSpec
的元类扩展
为图标选择图案
现在您可以为原型指定图形表示。您可以指定两个图像:一个用于 Project Explorer 下的图标,一个用于图中显示的图像。对于本练习,只指定图标图像。
确保在 Project Explorer 中选择了 SimpleServiceSpec,并单击 Properties
视图的 General 选项卡。
单击 Browse 选择图标,然后指定为 GIF 或 BMP 文件。我们为该图标提供一个 16x16 象素(推荐大小)的
GIF,如果愿意,您可以使用。
图标字段现在应该是 Defined。
添加属性
现在,向原型添加名为 source 的属性,以指定如何确定服务规范(例如,利用从商业过程任务或遗留应用程序)。
在 Project Explorer 中,选择 SimpleServiceSpec。
单击右键,选择 Add UML > Attribute。
将属性命名为 source(如图 6 所示)。
图 6. 创建新的原型属性
在 Properties 视图的 General 选项卡中,单击 Select Type ,并将属性的类型指定为
String。该属性,允许概要文件用户利用此原型,为被标注的元素提供额外的信息。在这种情况下,它们能够在确定规范的地方输入定义的
string。
对于本练习来说,您现在已经完成了您(非常)简单的概要文件的指定工作。图 7显示了结果。
图 7. 简单的服务概要文件
通常的下几个步骤
下面您一般要进行的几个步骤是您的概要文件的约束条件和枚举的规范。
约束条件限制了概要文件及其中元素的使用方式。例如,您可以创建一个约束条件,以确保当有人无论什么时候创建
SimpleServiceSpec 的模型元素时,它们都必须指定一个源。如果用户没有指定源,那么模型元素上就会指示有错误,,并提供描述该问题的消息。
通过与为原型创建的属性相关联来创建并使用枚举类型。与其让用户输入用来指定属性值的文本,您不如要求他们从列表中选择一个值。列表中的值将通过概要文件中创建的枚举来提供。
为了保持本练习的简单,您在此不用执行这些步骤。
测试及发布您的概要文件
现在,确保您可以将概要文件应用于模型中。
保存概要文件(CTRL + Shift + s)。
每次您保存概要文件时,都会创建它的新版本。现在,精简概要文件,去除所有不必要的版本,只留下最新的一个。
选择 Project Explorer 下面的 SimpleServiceProfile,单击右键,然后选择
Compress。
单击 Yes。
现在您需要确保您不会对概要文件进行变更了,因为那将严重影响概要文件的用户。要这样做,您需要发布您的概要文件。
4 选择 Project Explorer 下面的 SimpleServiceProfile,单击右键,然后选择
Release。
指定 test release 为发布标签。您应该会看到 profile.epx 文件(图 8)中的结果。
图 8. 概要文件版本
提示:
当您发布一个概要文件时,向您的用户提及,概要文件的变更不会对他们带来负面的影响。Rational Software
Architect 通过禁止您去掉发布概要文件中任何元素来保证这一点。当概要文件发布之后,您可以增加概要文件,但是不能对其进行变更。
在此阶段,最佳实践推荐是将您的概要文件打包成插件,并将其应用到您的组织中。然而,出于本练习的原因,您可以通过选择您在工作区中创建的概要文件来执行简单的测试。
创建带有默认类图的新的 UML 工程和模型。这是您应用概要文件的模型。
确保选择了 Project Explorer 中的新模型,然后选择 Properties 视图中的 Profiles
选项卡,并单击 Add Profile。
在 Select Profile 对话框中,选择 Profile in workspace,然后指向 SimpleServiceProfile.epx(图
9)。
单击 OK。
图 9. 选择工作区中的概要文件
在类图中创建新的 UML Interface(在选项板中),并将其命名为 IClaimRecorder。
确保选择了 IClaimRecorder,然后选择 Properties 视图中的 Stereotypes
选项卡,并且单击 Apply Stereotypes。
您现在应该可以使用刚创建的 SimpleServiceSpec 原型了(图 10)。选择它,并单击 OK。
图 10. 应用新的原型
注意,现在 IClaimRecorder 的新图标和源属性都可用了(图 11)。
图 11. 应用于 IClaimRecorder
的 SimpleServiceSpec 原型
就这些了。您已经创建了一个简单的概要文件并且测试了它,从而确保了您可以将它应用于模型。实际中,当您到达了此阶段时,您会在插件工程中打包概要文件,将其部署为
RAS 资产,并提供给其他人使用。
如何创建和使用您自己的模板
在 Rational Software Architect 的环境中,template(模板)指的是用于不同用途的不同类型的模板:
页面模板:用这些模板来创建新的 HTML 或 JSP Web 页面。
UML 模板:用这些模板来创建具有同样特征的模型元素。UML 模板定义了一组可以绑定到其他模型元素上的模板参数。
代码模板:您可以为能够自动地插入的频繁使用的代码段使用这些模板,例如 get 和 set 方法,Java
代码中新方法的注释,或 XML 文档中的注释。
Java? Emitter (JET) 模板:这些模板使用 Java Server Pages (JSP)
语法来表示要生成的代码(例如,Java、XML、SQL)。本系列中第 2 部分更详细地介绍了这些模板。
模型模板:如这部分所介绍的,这些模板为模型提供了基本的结构。
Model templates(模型模板)的用途是定义具体类型的模型的结构,以及预定义的模型元素。设计人员之间可以共享模型模板,以确保一致性。此外,它们帮助您避免从一个空模型开始构建。在一些情况下,您的确需要从头开始的自由。然而,在许多其他的情况下,您将创建一个其他人以前已经工作过的领域中的模型。因此,模型模板为您的建模起了个头,这为用户在正确的方向上提供了优势及推动作用。
在“Design SOA services with Rational Software Architect,
Part 2”(参考资源中列出的文章)中,当讨论到 UML 2 Profile for Software
Services(服务概要文件)的可能用途时,我们谈到了模型模板。Rational Software Architect
的概要文件插件实际上包括了可以用于创建新的服务设计模型的模型模板。当创建新模型时,New UML Model
向导列出了可以用于创建模型的模型模板,包括空模板。可用的模板列表中包含了 Service Design
Model 模板,如图 12 所示。
图 12. New UML Model 向导
当您选择了 Service Design model 模板时,新创建的工程就已经将包、模型元素、可复用模型元素和图包含在内,以帮助您设计服务了,如图
13 所示。
图 13. Service Design
model 模板
创建用作模板的模型
在 Rational Software Architect 版本 7 中,任何模型都可以作为模板。因此,您创建模型模板所需要做的事情就是创建一个模型。您和其他人可以将该模型作为模板用于创建新的模型。
Rational Software Architect 的可扩展特性还允许您将模型注册为模板。在此部分中,您将创建一个简单的,基于“Design
SOA Services with Rational Software Architect”系列(参考资源中列出)中所使用的模型的结构的
Service Design model 模板。首先,您将创建一个新的模型,然后确保该模型可以用作模板。
创建 UML 模型
创建一个新的使用了服务概要文件,并拥有如图 14 中所描述的结构的 UML 工程和模型。如果您已经知道如何做到这些,那么您可以跳到下一个部分。否则,您就要依照本部分中的指导。
图 14. 工程结构
在 Modeling 透视图中,选择 File > New > Project。
在 New Project 向导中,输入 uml ,作为 Filter 字段。
选择 UML Project,并单击 Next (图 15)。
图 15. New Project 向导
将工程命名为 Service Design Model,并单击 Next (图 16)。
图 16. 新建 UML 建模工程
确保选择了 Templates 下的 Blank Model。
输入 Service Design Model 作为 File name,并确保在新模型中创建 class
diagram ,如图 17所示。
单击 Finish。
图 17. New UML Model 向导
提示:
如果您单击向导左下的 ? 图标,就可以使用动态帮助(图 18)。
图 18. Dynamic Help 选项
配置 UML 模型
现在您将配置 UML 模型,使之可以使用服务概要文件。
在 Model Explorer 下,确保选择了 Service Design Model(图 19)。
图 19. Project Explorer
中的初始 UML 模型
在 Properties 视图下(图 20),选择 Profiles 选项卡。您可以看到默认应用于 UML
模型的概要文件。您现在将把 Software Services 概要文件添加到列表中。
图 20. 应用于模型的概要文件
单击 Add Profiles,然后选择 Deployed Profile 下面的 Software Services
。
单击 OK。
创建包结构
下面,您将创建 UML 模型的结构,也就是三个包:
Messages
Service Specifications
Services
然后,您将连接这些包,以显示依赖关系。
Rational Software Architect 在每个新的包下面默认地创建任意的图。首先,您将要变更参数选择,以便在每个新的包中生成一个类图。
选择 Window 菜单下的 Preferences 。
在 Filter 字段中,输入 default,并选择 Default Diagrams(在 Modeling
之下)。
将 Default diagram type 改为 Class Diagram。
单击 Apply,然后单击 OK。
选择 Main 类图,并将其重命名为 Main - Service Design Model ,按 F2(如果提示,就保存模型)。
选择 Service Design Model。
单击右键,选择 Add UML > Package,如图 21 所示。
图 21. 创建新的包
将包命名为 Messages。
将 Main 类图重命名为 Main - Messages。
同样地,分别创建其他两个名为 Service Specifications 和 Services 的包,然后将它们的
Main 类图重命名为 Main - Service Specifications 和 Main - Services。图
22显示了结果模型。
图 22. 新建的包
创建包依赖关系
现在您将创建这些包之间的依赖关系。
如果没有打开,那么就打开 Main - Service Design Model 类图。
从 Model Explorer 上将三个包拖到图上。
要添加从 Service Specifications 到 Service Message 的使用关系,将您的光标放在
Service Specifications 上,单击 outbound arrow,按住鼠标按钮,将光标拖到
Service Messages 上,然后释放您的鼠标按钮。
接下来,选择 Create Usage(图 23)。
图 23. 创建使用依赖关系
利用同样的技术,创建 Service 和 Service Specification 之间的使用依赖关系。结果图如图
24 所示。
图 24. 包依赖关
图 25 显示了 Project Explorer 中的结果工程视图。注意 Services 和 Service
Specifications 包之下的使用依赖关系。
图 25. 新的工程结构
全部保存(Ctrl + Shift + s)。
在这个简单的实例中,您在模型模板中只加入了包和图。然而,在您的模板中还可能包含其他模型元素(类、接口,等等)。
提示:
当使用 Rational Software Architect 中所包含的模型模板时,注意每个模板都有一个
Reusable Building Blocks 包。这组元素背后的意图是有许多元素在重复的结构中常常一起使用。与其编写重复的结构,不如从
Reusable Building Blocks 文件夹中复制粘贴,从而加速模型的使用,并且保持模型是根据最佳实践构成的。当创建您自己的模型模板时,牢记这一思想,并构建您的模板,以提供类似的功能。
在下一部分中,您将导出刚刚创建为模型模板的模型。
提供作为模板的模型
在 Rational Software Architect V7 中,您可以根据现有的创建新的工程或模型(不仅根据已注册的模板)。Rational
Software Architect 使您能够选择模型或工程(图 26),并且它可以创建一个新的模型或工程,作为您刚选择的工程的复制品(拷贝)。新的工程包含所有来自原始模型中的模型元素和图。
图 26. 来自现有模型的新 UML 模型
(可选)将模型注册为模板
将模型注册为模板,以便与成品模型模板一起使用是可行的。要做到这些,您要使用
Rational Software Architect 的 extensibility 能力和 com.ibm.xtools.modeler.ui.wizards.templates
扩展点。例如 com.ibm.xtools.modeler.ui.templates 插件向您展示了如何利用扩展点。在本教程中我们不介绍如何做到这些。
选择 File > New > UML Model。
在 New Model 向导的第一页上,选择 Existing model,然后单击 Next。
在第二页上(图 27),单击 Browse,然后选择 Service Design Model.emx。
在 File name 字段中,输入 a model name,然后单击 Finish。
图 27. 新建 UML 模型规范
Rational Software Architect 利用 Service Design model
作为模板,创建了新的模型。
结束语
在本教成中,您已经看到了 Rational Software Architect 采用许多不同的方式让您获取并自动化存在于组织和行业之中的最佳实践。尤其是,您学到了创建定制的概要文件和模型模板的方法。概要文件使您能够定制
UML,以便您可以将其用于 SOA。当您裁减完该语言之后,模型模板使您能够指导概要文件的用户得到设计良好的模型和解决方案。本系列未来的教程将告诉您如何在模型中,和在模型之间将最佳实践自动化。
技术环境的现实是您将不断地面对更快地完成更多任务,以及遇到更严格的质量标准的压力,您的团队的工作环境的跨度不仅是企业范围内了,而是全世界范围。这些自动化工具可以使您提高生产力、增强架构完整性,并提高软件质量。
|