2.1 Abstract Factory(抽象工厂)
当用户需要应用程序为他们提供一系列不同的对象,而这些对象又属于同一范畴且具有一定的相互关联时,我们可以用抽象工厂模式来为用户提供一个统一的接口而无需他们自行选择具体由哪个类来创建哪个对象。
我们以Dell公司为例,Dell公司生产不同的计算机及元件(不考虑OEM这种具体的商业模式,暂且看做是由Dell公司自行生产的),例如它可以向用户提供台式机、笔记本电脑、打印机、显示器等等计算机硬件,而用户需要购买Dell的产品时不会具体去联系Dell相关的生产车间,而是由官方网站这个统一的界面来订购自己需要的产品,至于Dell内部是如何从无到有地生产出这个用户需要的产品,用户则完全不需要关心了。同时我们也可以看到,无论用户购买的是Dell的台式机或是笔记本抑或是打印机,总之他拿到产品时一看就知道是Dell的,绝对不会错认为是Apple的,因为所有Dell的产品都会保持统一的风格(无论是商标还是设计风格)。
那么,我们如何用程序来描述上面的场景呢,首先,我们需要有一家工厂,但是“工厂”这个概念太笼统了,因为每一件产品并不是由“工厂”这个概念生产的,而是由某家具体的工厂实体中的某个具体的车间生产的,因此我们给出一个抽象类,并由Dell这家实体工厂去继承它,并调用它内部那些生产Desktop或者Laptop的车间来创建具体的产品,接下来我们来看看示例代码吧:
1: using System;
2:
3: namespace Autumoon.DesignPatterns.AbstractFacotry
4: {
5: public class ProductBase
6: {
7: public const string Logo = "Dell";
8: }
9:
10: public class DesktopProduct : ProductBase
11: {
12: public string CPUInfo { get; set; }
13: }
14:
15: public class LaptopProduct : ProductBase
16: {
17: public double Inch { get; set; }
18: }
19:
20: public abstract class TheAbstractFactory
21: {
22: public abstract DesktopProduct CreateDesktop();
23: public abstract LaptopProduct CreateLaptop();
24: }
25:
26: public class DellFactory : TheAbstractFactory
27: {
28: private static DellFactory _instance = null;
29: public static DellFactory Instance
30: {
31: get { return ((_instance == null) ? _instance = new DellFactory() : _instance); }
32: }
33:
34: public override DesktopProduct CreateDesktop()
35: {
36: return new DesktopProduct { CPUInfo = "Intel(R) Pentium(R) 3.40GHz" };
37: }
38:
39: public override LaptopProduct CreateLaptop()
40: {
41: return new LaptopProduct { Inch = 14.1 };
42: }
43: }
44: }
我们有TheAbstractFactory这样一个抽象类,它给出了统一的创建产品的接口,DellFactory这个具体类继承了该抽象类并改写了其中的抽象方法,从而用户只需要调用DellFactory示例中相应的方法即可获得相应的产品,而不需要关心该产品到底是由谁如何生产出来的。并且我们可以看到DellFactory采用了Singleton模式,因为具体的工厂或车间部门一般都是唯一的。不同的车间生产不同的产品,但这些产品又都属于Dell产品系列,所以必然有一定的联系,在我们的示例代码里,这种“联系”就表现为具有相同的Logo。
接下来我们来看看客户是如何让Dell生产他们所需要的电脑吧:
1: DesktopProduct desktop = DellFactory.Instance.CreateDesktop();
2: LaptopProduct laptop = DellFactory.Instance.CreateLaptop();
抽象工厂使用户与具体相关的类分离开来,并且还有利于保持产品的一致性,但是这种方式并不能很方便地支持新的产品类型,每一次增加新的产品类型时都需要扩展该工厂接口,这可能使得抽象工厂类和它的所有子类都不得不发生相应的变化。