一起谈.NET技术,在.NET中使用域对象持续模式

  域应用程序对象通常是整个应用程序的中心,被很多子系统使用。它们表现了核心的数据和业务验证规则;因此,良好的域对象设计对于牢固的、高性能的和灵活的应用程序非常关键。

  当我们开发那些使用了关系数据库的面向对象应用程序的时候,建立与数据库设计一致的域对象设计可以使应用程序更容易理解,这是因为在典型情况下,域对象表现了现实的"实体"和它们彼此之间的关系。因此,在很多情形下,域对象都被"映射"为关系数据库表和表间关系。但是,这种映射非常容易出错,从而以不合需要的域对象设计为终结。域对象的良好设计要求开发者对面向对象和关系的基本原理有深刻的理解。

  域对象持续(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传递到分布式应用程序),而不需要暴露持续性代码。

时间: 2024-08-02 17:41:10

一起谈.NET技术,在.NET中使用域对象持续模式的相关文章

在.NET中使用域对象持续模式

域应用程序对象通常是整个应用程序的中心,被很多子系统使用.它们表现了核心的数据和业务验证规则:因此,良好的域对象设计对于牢固的.高性能的和灵活的应用程序非常关键. 当我们开发那些使用了关系数据库的面向对象应用程序的时候,建立与数据库设计一致的域对象设计可以使应用程序更容易理解,这是因为在典型情况下,域对象表现了现实的"实体"和它们彼此之间的关系.因此,在很多情形下,域对象都被"映射"为关系数据库表和表间关系.但是,这种映射非常容易出错,从而以不合需要的域对象设计为终

一起谈.NET技术,.NET 中的二进制浮点类型

大多数人会对他们在.NET中的算术的"出错"首先感到惊讶.使用一些称为"浮点"算术来表示非整型数字不是.NET 相比其他大多数语言/平台特殊的地方.在.NET 内部是没问题的,但是你需要知道一些底层正在发生什么,否则你将会对一些结果感到惊讶. 我在这个事情上不是一个专家这不重要.虽然写了这篇文章,我也发现了另外一篇 - 这次是一个真正的专家写的,杰弗里 萨克斯(Jeffrey Sax).我强烈建议你也同时读他的浮点文章. 什么是浮点数? 计算机总是需要一些表示数据的

一起谈.NET技术,.NET中的异步编程(二)- 传统的异步编程

在上一篇文章中,我们从构建响应灵敏的界面以及构建高可伸缩性的服务应用来讨论我们为什么需要异步编程,异步编程能给我们带来哪些好处.那么知道了好处,我们就开始吧,但是在异步编程这个方面,说总是比做简单.套用那句不是名言的名言:编写异步程序是困难的,编写可靠的异步程序尤其困难.因为异步程序非常难以编写,而且非常容易出错,很多基本的构造元素在异步编程中都无法使用,这让我们这些开发人员更愿意编写同步的代码,虽然我们知道有些地方真的应该使用异步. 如何实现异步 对于很多人来说,异步就是使用后台线程运行耗时的

一起谈.NET技术,VS2010中的调试技巧

这是我的博客中关于VS 2010和.NET 4发布系列的第二十六篇文章. 今天的博文将介绍Visual Studio中的一些实用调试技巧.这是受我朋友Scott Cate (他发表过几十篇很棒的VS技术文章) 启发.他最近告诉我,许多Visual Studio下的程序员,甚至一些很有经验的开发人员,都不知道这些技巧.希望这篇文章能帮你掌握这些技巧.它们都很简单,却能帮你节约大量的时间. 跳到当前光标处(Ctrl+F10) 我经常看到人们为了到达目标代码位置,而在程序中早早设定了断点,然后反复地按

一起谈.NET技术,Silverlight中自定义控件

自定义控件并不是一项多么难的技术,关于自定义控件这部分有不少文章讲的很透彻,这里我主要把自己练习自定义控件的过程记录下来. 这里我以自定义控件BusyPointer为例,首先我们新建一个应用程序,命名为CustomControl,这里我们将自定义控件放入单独的项目中,所以在解决方案里添加一个Silverlight Class Library项目,命名为BusyPointer,现在我们把Class1.cs类删除,然后在BusyPointer项目中添加一个Silverlight Template C

一起谈.NET技术,.NET 中的正则表达式

前两天面试一个程序员,自己说工作中用到过正则表达式,也比较熟悉,问他要使用正则表达式需要引用那个命名空间,使用哪些类,居然吱吱唔唔答不上来,让他写一个验证电话号码的正则表达式也写不出来,实在是很奇怪这种程序员是怎么工作了两三年的. 言归正传,下面介绍下.net中正则表达式中的使用. 要在.net中使用正则表达式,需要引用System.Text.RegularExpressions 命名空间.新建一个正则表达式类: string pattern = "some_pattern"; //正

一起谈.NET技术,C# 中奇妙的函数--联接序列的五种简单方法

今天我们来看看5种使用Linq函数联接序列的方法,这5种方法可以归入下列两类: 同类的联接 Concat() Union() 不同类的联接 Zip() Join() GroupJoin() Concat() – 串联序列 最简单的序列合并,concat仅仅是将第二个序列接在第一个序列后面, 注意:返回的序列并没有改变原来元素的顺序: 1. var healthFoods = new List<string> { "fruits", "vegetables"

一起谈.NET技术,.NET中锁6大处理方法 悲观乐观自己掌握

本文介绍了处理.NET中锁的6种方法,首先我们讨论一下并发性问题,然后讨论处理乐观锁的3种方法,乐观锁不能从根源上解决并发问题,因此后面我们介绍了悲观锁,最后介绍隔离级别如何帮助我们实现悲观锁,每个隔离级别都列举了示例进行说明,使得概念更加清晰. 我们为什么需要锁? 在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这就会产生冲突,这个就是著名的并发性问题. 图 1 并行性问题漫画 如何解决并发性问题? 借助正确的锁定策略可以解决并发性问题,资源被锁定后,其它进程想要访问它就会被阻止.

一起谈.NET技术,C#中的lock关键字

前几天与同事激烈讨论了一下,有一点收获,记录起来. 首先给出MSDN的定义: lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.这是通过在代码块运行期间为给定对象获取互斥锁来实现的. 先来看看执行过程,代码示例如下: 假设线程A先执行,线程B稍微慢一点.线程A执行到lock语句,判断obj是否已申请了互斥锁,判断依据是逐个与已存在的锁进行object.ReferenceEquals比较(此处未加证实),如果不存在,则申请一个新的互斥锁,这时线程A进入lock里面了. 这时假设线程