学习.NET架构设计系列:学用设计模式(2)
运用OO方法设计程序的时候会遇到的这样困难:我们从需求中发现了一些模糊的概念,但是怎样才能根据这些概念建立合理的对象模型呢,到底哪些概念应该是一个类,哪些概念只应该是一个方法和属性,这些类之间应该是什么样的关系?要解决这个问题,最根本的途径当然是尽量深入的了解需求(比如说翻翻会计原理,看看应收款未收和已收的时候应该如何记账,其中一个记账原则也许就是一个重要的对象;协助用户做一个供电方案,随手画出的草图,或者某个计算公式就是一个重要的对象)。在解决了一个个困难之后,有人总结了经验,形成了一些解决特定问题的固定套路,这样的套路就是设计模式。
有些设计模式和OO没有什么必然的关系,比如层次模式,消息模式。但是大部分设计模式都是在OO设计中形成的,这些模式可以帮助我们发现系统中的对象、设计对象之间的关系。了解这些模式可以帮助我们把软件设计的更加合理。并且,在探索需求的过程中,我们也可以从模式中得到一些启发,获得设计的灵感,发现需求的真实面貌。
在上一篇我们看见了“费用”这个类型:Fee,其实这就是一个简单的设计模式:组合模式(Composite)。这个类的结构如下:

Fee类型是他本身的一个聚合,可以使用GetChildren方法得到某个费用包含的其他费用。如果一个费用没有包含其他费用,他的金额就是由他自己确定的,否则就是由他包含的费用相加确定的,这两种情况对外界提供的都是相同的方法:GetValue。这样,我们想显示一个账单费用的时候,不用再去判断他是否包含了其他的费用,调用起来就简单了很多。组合模式很好的体现了账单费用的层次包含关系。
刚才的情况里面,聚合类和元素类都是同样的类型。也有些情况他们分别属于不同的类型。比如一个企业,他的营销网络是由下面一些元素组成的:公司,市场部,直销店,代理商,自由代理人,营业员。如同下面的情况:

公司按照行政区域建立了多个市场部,市场部建立了自己的直销店,同时也与很多代理商和独立代理人进行合作,直销店和代理商雇用了营业员。每天公司需要对每个销售网点的情况进行查询和分析,需要知道他们定下了多少订单、收了多少货款、发展了多少新的客户。
这是一个比较复杂的结构关系,网点类型比较多,他们的销售方式差异很大,各类数据统计的方式也不同。并且在统计一些数值的时候,需要把下属网点的数量加起来,再加上自身的数量。如果采用组合模式,就可以解决这种问题。

我们可以设计一个类,叫做销售单位(SaleUnit)。这个类是他本身的一个聚合,可以通过一个集合成员访问到他下属的单位。并且他的每一种下属单元也是SaleUnit的子类。各种销售网点统计数据的方式是不同的:有的数据保存在数据库表里面,经过一些统计运算可以得到;有的直接放在数据表的某个字段里面,直接查出来就可以了;还有的是每天发过来的一个Excel电子表格。对于每一种不同的销售网点,都可以使用一致的接口对他们进行访问,得到需要的数据。
组合模式可以很精确的反映销售网点间的聚合关系,并且对查询和统计提供了非常一致的接口,调用者不必区分具体的网点类型。类似这样的情况,当我们发现需求中一些对象具有聚合关系,并且我们希望对他们做一些共同的事情,就可以采用组合模式。
现在产生了一个严重的问题:是的,调用一个对象的确实没有必要去区分具体的网点类型了,但是他们是在哪里被创建的呢,创建的时候还是要区分网点的类型,复杂的代码只是从一个地方转移到另一个地方罢了,这样做有什么好处呢?为了解释这个疑问,下面会介绍另一个常见的模式:工厂模式(Factory)。
工厂模式用来彻底的断绝调用者和被调用的具体类型之间的关系,他使用一个工厂创建具体的类型,调用者从工厂中取得对象的实例。调用者既不需要知道对象是怎样被创建的,也不需要知道创建的是什么类型。下面通过一个例子说明一下工厂模式的用处。

