落魄青年,挨踢民工,已经转行
分类:
2007-10-19 15:02:13
业务对象是一个方案
现在我讲到这次演讲中最有价值的部分。我相信,业务对象是一个理想的解决方案。它不影响RAD快速开发程序的自由,同时提供了服务器端代码的安全和可靠性。业务对象提供了一条既不同于胖客户又不同于胖服务器的另外一种方案。一个适当设计的业务对象增加了代码重用性,并且允许你将业务规则放在一个单一的地方。通过业务对象对业务规则的集中存储,我们可以生产容易修改和维护应用程序。
并非所有的开发者都依靠数据库服务器。很多应用程序的开发者使用文件型数据库,比如foxbase,parabox,access表,如果你没有一个后端的数据库服务器,只有这些表文件,难道你又得把业务规则的代码粘到用户界面中去?不,业务对象提供一个地方存放业务规则,并且同时也提供了一个一致的可伸缩的应用程序体系结构,不管你是用基于SQL的数据库服务器还是基于文件共享的表数据库。
业务对象模拟真实的业务活动,业务活动中的业务规则用业务对象的方法来体现。业务对象有一个无形的好处,首先它能在用户和开发者之间增加沟通。其次,业务对象提供一条途径将复杂的问题分解成较小的可以解决的部分。正常地,复杂的业务问题由一些小点的次复杂的问题组成,次复杂的问题又由一些更简单的问题组成。
当我们实行良好的业务对象设计时,大的代码重用是可能的。使用继承和专门化软件对象(雇员对象就是一个人员对象的扩展)。在对象之间协作(一个薪水册对象不用去记录员工的信息,它只是包含和使用一个员工对象就够了)和在应用程序中共享对象,我们可以减少费用,减少新的应用程序开发周期。
定义业务对象
业务对象模拟真实世界的一个实体,它结合了数据和行为。
The central activity in working with objects is not so much a matter of programming, as it is representation...(此句不知如何翻译,原文放在此处)。在面向对象的开发中,每个重要的真实世界的对象或者概念都被一个软件对象所代,该真实对象的所有的数据和行为都被软件对象所代表。(David Taylor, Business Engineering With Object Technology, New York: John Wiley and Sons, 1995)
如果这个对象模型正确地表示了问题域,通过给某个对象赋予模型中的某个角色,我们就可以复制该对象的行为。(不太通顺,不知如何译)
关键业务对象概念
继承
从基类型产生一个新的派生类型,派生类型继承了基类型的数据结构和行为,但同时又作了一些增强和改动。Delphi 支持单继承,这就是说,你可以而且只可以有一个基类,但是Delphi支持一个类实现多个接口(interface).
封装
封装概念就是隐藏了实现细节。换句话说,你告诉我你能做什么,不需要告诉我你怎样做到的。良好设计的对象分离了它能做的和它是怎样做的部分。举例来说,如果你有一台轿车,它有一个方法是“开始”,它自己可能要检查油泵是否打开,档位是否合适,火花塞是否有电,等等,然后跑动起来,但是,你不用管这些具体细节。只要知道它能“开始”就行了。
多态
设计具有类似操作的对象可能具有相同的公开接口,但是他们具有不同的行为细节,这些细节依赖它们所在的类。还是以前面说的汽车为例,如果将它派生类化,生成一个电动汽车,电动汽车还是具有“开始”这个方法(或叫行为),在内部来讲,电动汽车的“开始”方法有不同于非电动车的行为,例如它没有油泵,当然不会去检查油泵。多态是这样一种机制,它可以覆盖基类的执行方法从而做它自己的事情。我们可以使用多态的方式用相同的透镜去观察不同的对象。
类别化
决定什么是一个对象和什么不是一个对象。这在面向对象设计中可能是一个最困难的任务,因为没有什么快速而且可靠的方法来达此目的。实际上,不存在理想的完美的途径。迟一点我将示范如何在一个给定的问题域中找出合适的对象。
协作/对象职责
类必须是自包含的,也就是说,它们必须处理它们自己被赋有责任的功能。一个对象可以和其它的对象合作来实现它的职责。对象可以包含其它对象,也可以创建和使用其它对象。为了完成一个任务,应用程序不必一定要创建两个对象,有时候只需要创建一个复合的对象就可以达到目的。
建立业务对象的原则
这里有一些建立业务对象的原则需要用心记住。
不要基于表现层建模
要基于实际的业务来建模,而不是用户界面的具体实现。基于用户接口的对象模型非常难于在其它应用程序中复用。
开发业务对象要能独立于图形用户接口(GUI)
为确保你的业务对象独立于表现层,一个方法是考虑让你的业务对象能被非图形用户界面使用(虽然不一定有这种实际的需求)。开发业务对象的个人或者团队首先不必考虑用户界面。然而一旦业务对象有了公开的方法和属性,你可以使用依赖这些业务对象的方法和属性来建立图形用户界面。
让业务对象实施业务规则
如果业务规则不能被业务对象实施,或者不能按设计意图实施,你必须在对象上注明它将在哪里实施,以及为什么要在那里实施。一个例子是一个后台存储过程从数据库中统计了很多信息,来判断你是否能处理某件事情,由于是针对数据库统计后的简单判断,就近处理有速度上的优势,因此,放置改规则在存储过程中可能是个好的设计。当另外一个程序员在看业务对象的代码时,他就能够知道这个规则不在本对象中实施,它在另外某个地方实施,以及它在另外地方实施的好处。
不要向GUI发消息
直接向GUI发消息将使你的业务对象在应用程序中缺乏可移植性。比方说,一旦你在业务对象的代码中写下了Form1.Label1.Caption:= `保存当前工作' ,那么你就失去了任何可重用的希望,因为其它地方可能根本没有Form1.如果你需要告诉用户一些事情,或者需要用一个对话框交互,可以专门为此目的设计一个对象。这也同样允许用户定制应用程序通知他们的方式(举例来说,在输入数据的时候,很多人都不希望出现一个消息框,把消息放在状态条可能更好)。而且,当你准备设计分布式业务对象的时候,你根本没办法直接向用户发消息,只能用回叫函数。
隐藏内部实现,不让GUI知道
业务对象发布的接口描述了业务对象可以做什么。使用业务对象的客户程序不需要,大部分情况下也不应该知道业务对象的数据是如何存储的,查询功能是通过什么方式完成的。当内部的规则以及数据访问可以改变,此时,大部分的公布的接口应该不受影响。有可能在业务对象的祖先类中定义了某个抽象方法,在后代类中却有大相径庭的实现。比如,某个业务对象隐藏了关于SQL database和 foxbase的信息,在查询的具体实现中,一个使用SQL 文本方式,一个用本地文件API,但是该业务对象的客户-图形用户接口,完全不知道。因为图形用户接口是通过业务对象公布的接口来工作的,而不是基于业务对象的具体实现。
技术上的方法(非业务的)不能放在公用接口中
不要在业务对象的公开接口中放置opentables, updatecache之类的技术方法。业务对象是基于真实世界建模的,它应该隐藏技术上的方法和具体实现。除非真实世界的对象的确有一个opentables的行为,否则在业务对象的公开方法中不要包含它们。如果业务对象隐藏了它的实现细节,一个 GetCustomer(查找一个顾客)调用可能会打开一个表, 或者一个TransferAccount方法(转账)可能删除和一条记录,更新一个汇总表并且插入一条记录到另外一个表. 只是这些对图形用户界面来说,是看不见的。