写在前面
最近一段时间在研究有关设计模式方面的文章,拜读了TerryLee以及吕震宇两位老师所写的设计模式方面的系列文章,收获颇丰,也让我对OOP,OOD有了新的理解和认识,不过在看到工厂方面的几篇文章时,却总有个地方想不通,望各位老师专家能替在下答疑解惑,以下是自己对工厂模式的一些理解以及提出的一种改良方案,不知道是否有人提出过类似的方案,如有雷同纯属巧合。有说得不对的地方还请批评指正。
从简单工厂说起
严格来讲简单工厂并不属于GOF的23个设计模式之一,但它之所以存在而被人们广泛认知的原因,我想是由于它在一定程度上简化了工厂方法(Factory Method)与抽象工厂(Abstract Factory)的模式,从而可以带给新手对于工厂模式设计的精髓最直观的认识,是不少人接触工厂模式的奠基石,理解了简单工厂的设计理念及实现方法再去理解相对复杂的工厂方法与抽象工厂有着水到渠成的效果。
先来看看简单工厂的类关系图:
简单工厂一般以如下方式实现:
2 {
3 /// <summary>
4 /// Get the right product base on the paoductcategory parameter.
5 /// </summary>
6 /// <param name="productCategory"></param>
7 /// <returns></returns>
8 public static IProduct CreateProduct( string productCategory)
9 {
10 switch (productCategory)
11 {
12 case " A " :
13 return new ProductA();
14 case " B " :
15 return new ProductB();
16 case " C " :
17 return new ProductC();
18 default :
19 throw new Exception( " Not a valid product category! " );
20 return null ;
21 }
22 }
23 }
客户对于简单工厂的使用
2 {
3 public void Do()
4 {
5 // Create a productA
6 IProduct product = SimpleFactory.CreateProduct( " A " );
7 // Product doing its tasks.
8 product.ExecuteFunction1();
9 product.ExecuteFunction2();
10 product.ExecuteFunction3();
11 product.ExecuteFunction4();
12 // More tasks .
13 }
14 }
这时,如果客户打算改为生产产品B,那么他需要做的仅仅是修改传入工厂的参数,以告诉工厂需要生产什么而对于后面产品所实现的功能不需要做任何的修改。简单工厂模式的最大优点在于工场模式包含了必要的判断逻辑,可以根据客户的需求动态生成客户所需要的产品,而在客户方面,免除了客户对具体产品创建的依赖,一句话:简单工场实现了对责任的分割。
说完了优点再来说说缺点,如果现在新增加了一种产品称作ProductC怎么办?OK,我们添加类ProductC、实现IProduct接口(注意,这个是由于新的业务规则所带来的变化,是任何模式都无法避免的),下面就是需要让我们的简单工厂具有生产这种新产品的能力,如何实现?你自然会想到多添一条case语句不就完了?然而事情并没有那么简单,因为你在添加case语句的同时也就意味着你修改了工厂类本身—违反了设计原则中最重要的一条OCP原则。开放封闭原则要求避免直接修改类而是应当通过继承来扩展类的功能。此外过多的case语句也容易混乱逻辑,造成工厂类的稳定性下降。那么对于新产品的增加,怎样才能妥善的处理并且又不违反设计原则呢?于是—工厂方法(Factory Method)登场了。
也谈工厂方法
先来看看工厂方法(Factory Method)的类关系图:
工厂方法一般以如下方式实现:
2 {
3 IProduct CreateProduct();
4 }
5
6 /// <summary>
7 /// 专门负责生产ProductA的工厂
8 /// </summary>
9 public class ProductAFactory : IFactory
10 {
11 public IProduct CreateProduct()
12 {
13 return new ProductA();
14 }
15 }
16
17 /// <summary>
18 /// 专门负责生产ProductB的工厂
19 /// </summary>
20 public class ProductBFactory : IFactory
21 {
22 public IProduct CreateProduct()
23 {
24 return new ProductB();
25 }
26 }
我们再看看对于新产品ProductC,工厂方法模式所采取的应对策略。首先仍然是要添加新的类ProductC,然后添加用于生产新产品的工厂类ProductCFactory并且实现IFactory接口,这样在保证能够实例化新产品的同时又没有修改已有的代码….Perfect? 别急,这时我们再来看看客户的代码:
2 {
3 public void Do()
4 {
5 // Create a ProductA
6 IFactory factory = new ProductAFactory();
7 // IFactory factory = new ProductBFactory();
8
9 IProduct product = factory.CreateProduct();
10 product.DoTask1();
11 product.DoTask2();
12 product.DoTask3();
13 product.DoTask4();
14 product.DoTask5();
15 // Do more tasks
16 }
17 }
这时你会发现,客户端需要决定实例化哪一个工厂来生产自己所需要的产品,判断逻辑仍然存在,仅仅是从简单工厂的内部逻辑判断移到了客户端代码进行逻辑判断。也就是说如果你要想最终生产出ProductC仍然需要修改代码,而只是这次修改的位置移到了客户端!