介绍
下面我要介绍的Bold for Delphi就是是一套优秀的基于UML模型驱动的面向对象的数据库开发框架包括了几十个组件组件以及个以上的类可以用来轻松地实现信息模型设计及基于信息模型的的应用程序
基础概念介绍
为了使大家对Bold for Delphi整个框架的使用有一个大概的了解下面将演示如何用UML设计一个简单的模型并用Bold来完成并包括如何用Bold快速实现一个简单的操作界面
自打我和我老婆认识以后就染上了她的臭毛病比较喜欢乱花钱没有节制结果搞的自己常常是挣的不如花的多老要借外债后来痛定思痛决定要对每月收支情况做预算严格控制费用支出为此写了还写了好多的财务小程序下面要讲的这个例子程序就是一个常见的家庭小账本程序它可以用来统计家庭中的收支情况软件的功能要求如下
可以定义家庭中的各个人员的信息
可以输入收支情况并同消费的人员关联起来
给出一定时期内消费的情况统计作为未来家庭预算的依据
建立信息模型
在产品的需求分析阶段我们首先要建立数据库程序的信息模型一般来说信息模型主要是指基于ER图的实体关系模型这是因为我们使用的数据库大部分都是关系型数据库虽然有些数据库比如Oracle有面向对象的特性但不是很完善一般很少使用而关系型数据库有一个很大的问题就是无法直观的体现面向对象的思想关系型的ER模型能够清晰地描述业务域的静态的数据视图但你无法从模型获取实体的操作及其相互之间的交互同时也很难在关系型数据库中简单地实现继承重载多态等等面向对象的技术因此现代数据库开发方法所提倡的面向对象的编程思想无法简单清晰平滑地映射为关系型数据库中的表结构
统一建模语言(UML)是一种以可视化的方式建立软件系统框架并进行文档化的语言UML语言是对当今软件工程领域成熟设计实践的一个总结并且已经被实践证明是可以成功地描述大型的复杂系统的目前国内很多的大型公司已经开始在软件开发过程中使用UML作为一种标准的信息模型设计语言了 Bold for Delphi就是基于UML的它内置了一套自己的UML建模工具当然我们也可以使用Rose或者ModelMaker来进行UML设计
面向对象的UML类图则可以说是对ER模型的一个扩展它对实体之间的关系以及相互之间的作用也进行了描述ER模型只是对要进行保存的数据进行的模型化而类图则包括了全部的类实体的属性以及它们的操作和相互作用它可以使我们对业务域问题有一个更精确的视图通过使用各种类图技术可以更容易地也更快速地建立正确的软件系统
基于Bold for Delphi的数据库开发革命性的一点就是允许我们直接把基于UML的类图映射为关系型数据库的存储而无须手工的通过代码进行转换要注意一点的是Bold同其它建模工具如TogetherModelMaker不同它生成框架代码时只使用了UML中的类图而Together等可以利用UML图中的类图协作图等其它UML元素来生成代码框架但是Together不负责生成对象模型对应的关系数据库模型
类模型
下面的这个类图就是我们的账本程序的一个简单类图
图中显示了两个类人员信息类Person以及账目信息类AcctItem人员类和账目类之间的连线描述了两个类之间的关系关系包括一个标题PayAssoc揭示了两者之间的关系是支付的关系每个属性PayPerson和Pay以及关系多重度因子和n表明每个人可以完成多个账目的收支而每个账目至少要有一个关联的人员同时类图还描述了下面一些业务规则
一个人的信息要有名称
账目信息中包含收支金额大小以及发生日期
上面的类图如果使用关系型数据库来实现的话需要建立主从表并将人员和账目之间的关联约束通过应用程序代码强制一些运行逻辑来完成这时通常要通过补充详细的文档来描述需要强制的业务逻辑如果没有详细的设计文档实现代码时就很容易遗漏某些重要的商业规则同时这些文档在整个的数据库开发的生命周期里面都需要人来手工地维护难免会出现文档和模型不匹配的错误而且文档的工作量比较大而程序员数量又相对不足的话程序员会觉得既要写代码又要写文档无形中增加了很多工作量难免会有抵触情绪这些都会影响工作的效率
对于这样的问题Bold则通过精确描述信息模型无须详细规则描述文档可以将模型自动的转变为实现代码商业规则在整个数据库开发生命周期内由Bold的类来维护减少了文档的工作量和出错的可能
建立示例程序
首先我们要安装Bold for DelphiBold的一个月评估版可以从wwwboldsoftcom获取同时D的架构版内置了Bold这里我就不详细介绍申请和安装的过程了安装好后Bold会在IDE的组件面板中添加很多组件接下来我们就开始建立使用Bold的Delphi程序了
在Delphi中选File|New Application创建一个新的应用程序
保存窗体文件为MainFormpas保存工程文件为CMoneydpr
添加一个数据模块设定数据模块的名字为DmMoney
将数据模块保存为CDataModulepas
为了使用Bold来建立系统的信息模型要进行下列操作
从Bold Handles 组件页上选择BoldModal(命名为bmMoney)BoldSystemTypeInfoHandle(命名为bsthMoney)和BoldSystemHandle(命名为bshMoney)到数据模块中
设定bsthMoney的BoldModal属性为bmMoney
设定bshMoney的BoldSystemTypeInfoHandle 属性为bsthMoney
其中BoldModel组件将被用来保存模型即类类的关系约束以及类型等这些信息将在设计时作为字符串保存到Delphi的窗体和数据模块文件中在运行时Bold将执行一些模型的中间转换过程将模型转化为BoldSystemTypeInfoHandle控件所使用的格式并选择实现可持续性的机制
在设计时储存在BoldModel组件中的信息模型可以被看做元数据就象数据库的库表和字段结构一样的信息而BoldSystemTypeInfoHandle组件则保存BoldSystemHandle所需要的运行时信息这些信息是对UML模型的一种运行时的表达这个组件是其他Bold组件的信息源
BoldSystemHandle组件则被用来表达整个系统的业务域元素可以理解为对象空间通过对象空间我们可以在运行时获得设计时元数据表达的对象的运行实例目前用到的三个控件已经可以很好的应用在不需要保存数据的环境中了但账目记录这类数据库程序必须要保存用户输入的信息因此还需要添加支持数据可持久性的控件这里为了快速演示的需要我们使用XML文件作为存储介质接下来要添加XML可持续控件到数据模块中
从Bold Persistence组件页上选择BoldPersistenceHandleFileXML控件(命名为bphxMoeny)添加到数据模块中
设定组件的BoldModel属性为bmMoney控件
设定bshMoney组件的PersistenceHandle属性为bphxMoeny组件
现在组件关系示意图如下
BoldPersistenceHandleFileXML组件将使我们的程序可以使用XML文件来保存和读取对象这是一个使用很方便的控件特别是在快速原型设计期间因为在原型设计期间模型经常会被改动而重新生成数据库表是很费时间的而XML文件可以使我们非常快的变更我们的模型设计当模型基本稳定后可以去掉这个控件转而切换为其他使用关系型数据库进行存储的可持续性控件这样的开发方式可以使我们不需要改动整个程序就能很容易地改变数据持续层的存储策略也就是前面所说的数据库平台无关设计
除了前面的一些基本的属性设置外我们还要设定下列控件属性
组件属性值说明bsthMoneyUseGeneratedCodefalse是否使用bold生成类代码
这里暂时先不使用
稍后我们会进一步介绍bphxMoenyFileNameData
xml指定保存数据的xml文件名bshMoneyAutoActivatetrue告诉Bold控件在程序运行后马上打开xml文件用于数据存储
建立模型
下面的步骤是建立我们的模型Bold for Delphi内置了一个树形的UML建模工具(应该说Bold美中不足的一点就是没有提供象Visio和Rose那样基于拖放的模型设计界面)我们可以双击BoldModel(bmMoney)组件调出模型设计工具bold UML模型编辑器(见下图)包含了应用程序模型信息数据类型信息和关系数据库映射信息
模型编辑器支持下列实体类型
Model: 模型全部业务域实体集合
Package: 包整个模型的一个子集所包含的实体可以将大模型分解为小模型来减少系统复杂度
Class:类类似于Delphi的类的概念(Delphi的类可以从UML的类来生成)但包含Object Pascal无法直接描述的类的信息和相互关系Bold框架通过关联类和特殊的列表类封装了一些额外的功能使得我们可以很容易的处理复杂的类关系
Attribute: 属性类似于Delphi中的property概念然而在Bold中这些属性可以在模型中直接保存而无需我们编写属性的GetSet方法
Operation: 操作等价于Delphi中的类的过程和函数
Association: 关联代表了类之间的关系关联可以使用类来表达关联也可以有操作和属性在Bold中建立关联的复杂工作同样可以由框架来实现我们无须编写代码来完成
Role: 角色代表关联同类的连接
Data Type: 表示模型所支持的不同数据类型它可以被扩展以支持用户自定义的数据类型
下图是不同实体类型在模型编辑器中是如何标识的
所有的实体类型都可以通过编辑器的右键菜单来创建和修改属性同时我们选中实体节点后实体和全局的选项会显示在右侧的编辑器中其中重要的有
Name: 模型的名称
Unit name: 指定Bold根据模型生成Delphi类的pascal单元的名称(前提是我们选择生成代码这里也可以选择不生成代码)