重温经典之《企业应用架构模式》——.NET中的架构模式运用 (Base Patterns 2)

忙了两天,继续我的随笔。

今天来看的,是另外几个基本模式。这些基本模式很多都已经发展的非常成熟,以至于现在大家都不习惯称其为模式了。但是我还是决定继续了解一下这些模式的来龙去脉,这样能够让我们对现有的一些用法有更加透彻的领悟。

Registry模式

在架构设计中,我们总关注各种各样的对象以及各个对象之间的关系,我们经常new一个对象,然后由一个对象的产生多个对象,如此反复。但是这一切复杂的关系,总得需要正确一个开始,第一个对象从哪里开始呢?

我们经常在系统中引入一种全局的对象,这种对象对他作用域中所有程序都是已知的,任何程序都可以直接通过这个全局对象来获得一个对象实例,并由此开始一系列的操作。这种引入全局对象的操作方式在这里就被称作为Registry模式。

这样的说法是抽象的,换句话说,Registry模式,就是在系统中定义一个用于获得其他对象实例的全局对象。

这种模式的目的在于“获得对象”,就好象读取配置需要获取配置文件对象,权限管理需要获得权限管理对象。在面向对象编程中,一个对象的实例往往是通过new关键字获得的,也许你会问,那为什么这里还要创建专门的全局对象用于“获得对象实例”呢?这里就是这个模式的重点。

之所以我们要使用一个专门的对象用于对象获取,就是因为我们对new这个操作不放心,一个最简单的要求是,我们经常要求获得的对象实例是全局唯一的。

到这里你也许会想到Singleton模式,没错,这种最简单的Registry就是使用Singleton实现的。在书中也有大量的代码来说明了如何使用Singleton实现一个Registry对象,实际上大多数情况下我们使用Singletom模式也就足够了。因为我们很多时候所需要完成的事情,就是“要求获得的对象实例是全局唯一的”。

确实是这样的,但是思考一下,还会有其他需求吗?

设想一个打印文件系统的场景,任务队列里有非常多的任务,每次处理一个任务,都需要获取一个打印机对象,而打印机对象是极为有限的,比如只有5个。

我们决定获取打印机(Printer)对象的时候使用Registry模式。在系统中定义一个全局PrinterRegistry对象,理想情况下,我们希望每调用一次PrinterRegistry.GetAvailablePrinter方法就能够获得一个可用的打印机对象,参考Singletom模式,我们可以写出类似这样的代码:

 

Code

 

这只是实例代码,并非完善的项目代码。始终要记住,这段代码并非线程安全的,还需要适当的使用lock锁来确保线程安全性,代码就不写了。

有了这样的代码之后,我们已经不能通过Printer printer = new Printer()来获取一个打印设备了,需要获得一个Printer对象,我们需要用这样的语法:

Printer myPrinter = Printer.PrinterRegistry.GetAvailablePrinter();

当然具体的实现也可以多种多样,书上还提到使用Hash表存储对象的方法,但是不论如何实现,总的思路不变,用一个全局对象控制对象实例产生,Registry模式。

 

下面我们来看看.NET框架中的使用,C#中静态类的出现让这种类似的Registry实现变得更加简单。实际上我们在.NET中更多时候把它叫做”Provider”,比如ASP.NET2.0中的成员管理(Membership)调用类:

public static class Membership…

这个静态类本身其实就是一个Registry,他自己负责利用web.config中定义的MemberProvider初始化自己,然后把自己返回给使用者。

实现多种多样,可以慢慢体会。

 

Value Object模式

         对于一个对象来说,我们经常操作的都是对象的引用,但是如果这个对象专门用来保存值,那么依然操作对象的引用就会引起莫名其妙的麻烦,最经典的例子莫过于下面这样的代码:

            Person p1 = new Person() { Name = "aaa" };

            Person p2 = p1;

            p2.Name = "bbb";

改变p2的值后,p1的值到底要不要改变?直觉告诉你要。

    牵扯到更复杂的,假设真的按照Java或者C#宣传的一样,“一切都是对象”,那么连Int32类型都是对象,那么执行这样的代码之后

            Int32 i = 3;

            Int32 j = i;

            i = 4;

         j的值到底要不要随着i变化呢?直觉告诉你不要。

         Person对象和Int32都是对象,为什么他们不一样?

         如果你对.NET不是很陌生的话,也许你脱口而出,这不就是值类型和引用类型的区别吗?

         没错,.NET平台和C#语言提供了强大的语言级别的支持,来帮助我们完成区别对待值类型和引用类型的工作,关于C#中值类型和引用类型之间错综复杂的关系,建议大家参考Jeffrey Richter所著的著名的”CLR Via C#”一书。

         其实如果你真的体会到了Value Object这种模式所面临的问题,再去读传说中的CLR Via C#理解起来就真的容易多了。

         Java中也有类似的东西,而如果你使用C++的话,就得费上不少的功夫来思考“引用”还是“值”得问题了。

伟大的平台,帮我们做了太多事情,让我们变成傻瓜。

Money模式

         我真的服了Martin大叔,居然把Money也算成一种模式,说起来Money模式就是一个用来专门处理“钱”的类。

         事实上,我们一般就用double类型或者float类型来存储“钱”的问题,但是真正遇到商业上货币的计算,用这种浮点类型就有麻烦了,最大的问题就是虽然浮点类型能保存小数,但它真的不是精确存储的。而精确,却是和“钱”打交道的第一要素!

         从这个意义上说,Money模式的诞生无可厚非,但是我依然很难接受把它归类到“企业架构模式”中去。

         想想.NET中的实现,很自然就会想到Decimal类型。

         首先Decimal是一个struct,也就是“值类型”,其次Decimal几乎封装了所有和专门用于货币计算的相关方法。Decimal详细的用法可以参考MSDN

         我只能说,Money模式已经发展的相当成熟,甚至成了.NET框架中的一个再平常不过的类型了。

posted on 2008-09-05 18:15  Yuxin Yang  阅读(710)  评论(0编辑  收藏  举报