当我们开发那些使用了关系数据库的面向对象应用程序的时候,建立与数据库设计一致的域对象设计可以使应用程序更容易理解,这是因为在典型情况下,域对象表现了现实的”实体”和它们彼此之间的关系。因此,在很多情形下,域对象都被”映射”为关系数据库表和表间关系。但是,这种映射非常容易出错,从而以不合需要的域对象设计为终结。域对象的良好设计要求开发者对面向对象和关系的基本原理有深刻的理解。
域对象持续(Domain Objects Persistence)模式试图提供一种向关系数据库的映射关系,解除域对象与持续性逻辑之间的耦合关系。在这种模式中,域对象自身是不知道持续性机制的,因为其依赖关系是单方向的(从持续性对象到域对象)。这简化了域对象的设计,使它们更容易理解。它也向应用程序中的那些使用了域对象的子系统隐藏了持续性对象。更好的是,这种模式可以在分布式系统中使用,在这种情况下,只有域对象四处传递,使应用程序不用把持续机制暴露给外部代码。本文演示了如何使工厂(Factory)模式和域对象持续模式一起工作,来帮助域对象与持续性逻辑解除耦合。
定义问题
域对象是所有应用程序的中枢。它们捕获了数据库的核心数据模型和应用在数据上的业务规则。在典型情况下,应用程序的大多数子系统都依赖这些通用的域对象——这意味着域对象的映射越接近数据库大纲,应用程序开发者理解和使用它们就越容易,因为它们表现了数据库中的现实”实体”和”关系”.
如果域对象没有与应用程序的其它部分分开,你通常就得把持续性代码复制到很多个位置。同样,如果域对象没有与持续性代码分开,你遇到的情况就是,任何使用域对象的子系统都必须知道并依赖持续性对象。对持续性对象的任何更改都必然影响整个应用程序。因此,如果没有把域对象与应用程序和持续性代码分开都是不好的设计。
定义解决方案
实现上述目标的一个途径是把域对象分离到一个独立的子系统中,让应用程序的其它部分需要域数据的时候再使用它们。此外,你还必须把域对象与持续性代码分开。一方面,这种双重分离避免了代码重复;另一方面,它向域对象隐藏了持续性细节信息,建立了更容易修改的灵活设计。无论数据来自关系数据库、XML文件、平面文件、活动目录/LDAP或其它任何数据源,域对象和应用程序的其它部分都完全不会受到影响。
在分离持续性逻辑和域对象的过程中,你必须确保域对象没有依赖持续性代码。这样操作允许你把域对象暴露在那些你不希望暴露持续性代码的地方。
建立示例
下面的C#示例使用了Northwind示例数据库的Customer对象,它映射到数据库的Customer表。
public class Customer
{ // 私有数据成员
String _customerId;
String _companyName;
String _contactName;
String _contactTitle;
public Customer() {} // Customer对象的属性
public String CustomerId
{get { return _customerId; }
set { _customerId = value;} }
public String CompanyName
{get { return _companyName; }
set { _companyName = value;} }
public String ContactName {get { return _contactName; }
set { _contactName = value;} }
public String ContactTitle {get { return _contactTitle; }
set { _contactTitle = value;} }}
public interface ICustomerFactory { // 用于单行操作的标准事务方法
void Load(Customer cust);
void insert(Customer cust);
void update(Customer cust);
void delete(Customer cust); // 返回集合的查询方法
ArrayList FindCustomersByState(String state);}
public class CustomerFactory : ICustomerFactory{ //用于单行操作的标准事务方法
void Load(Customer cust)
{ /* Implement here */ }
void insert(Customer cust)
{ /* Implement here */ }
void update(Customer cust)
{ /* Implement here */ }
void delete(Customer cust) { /* Implement here */ } //返回集合的查询方法
ArrayList FindCustomersByState(String state) { /* 此处是实现代码 */ }}
下面的示例演示了客户端如何使用这段代码。
public class NorthwindApp
{ static void Main (string[] args)
{Customer cust = new Customer();
CustomerFactory custFactory = new CustomerFactory();//从Northwind数据库载入客户
cust.CustomerId = “ALFKI”;custFactory.load(cust);// 传递Customer 对象
FooBar(cust);// custList是Customer对象列表
ArrayList custList = custFactory.FindCustomersByState(“CA”); }}
在上面代码中,load方法根据CustomerID(应用程序可以把这个值传递到任何子系统中而不需要暴露持续性代码)从数据库中载入Customer对象。同样,如果你载入Customer对象的数组列表,你随后也可以传递数组列表,也没有持续性代码依赖。
使用域对象持续模式分离持续性代码和Customer对象,使得Customer对象更加面向对象,更易于理解,因为它的对象模型更加接近于数据库中的数据模型。此外,这种分离使你能够把Customer传递到应用程序的不同部分(甚至于通过.NET Remoting传递到分布式应用程序),而不需要暴露持续性代码。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
.NET架构师:函数式语言做领域驱动设计
Scott一位.NET架构师,同时也是掌握函数式编程的作者,他很欣赏函数式编程,对于Scott来说,面向对象编程的那些概念也很恐怖,比如多态、泛型、继承、协变等。
-
软件开发就像炒股 关键看你怎么选股票!
本文作者Paulo Ortins在这里分享了对于选择哪种编程语言作为软件开发工作的起点的话题,并阐述了自己的观点。
-
增进离岸Java开发效率的十个提示
近日,Cygnet Infotech公司发布了一篇博文,谈到了如何增进离岸Java开发的效率。众多的ISV与软件厂商总是在不断寻找能以最低的代价实现其业务目标的解决方案。
-
Visual Studio 2013增强调试功能
Visual Studio 2013包含了若干诊断特性,能够帮助开发人员有效地调试他们的应用程序。