温故知新(4)——抽象工厂模式
概述
工作中,我们经常需要创建一组对象,这组对象相互相关或者依赖,形成一个系列,系列中的对象不能与其他系列中的对象混用。为系列中的每种对象建立工厂可以满足对象创建的需求,但是无法保证它们是同一系列的。这时引入抽象工厂模式可以解决上面的问题。下面是GOF给出的抽象工厂模式的意图。
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
抽象工厂的优点:
1、客户端不依赖具体实现类,符合依赖倒置的OO原则;
2、可以生成一系列的对象,生成不同的系列的切换比较方便,同时也可以保证一致性;
但是如果在新的系列中增加新类型,将会引发所有工厂类的修改。
如果注意观察,会发现很多框架的扩展点就是使用抽象工厂模式实现的,比如WCF、Unity等等。
抽象工厂模式比较常用,而且主要的是为了实现依赖倒置,所以实际中很多情况下都是用DI框架完成实现了。
结构
抽象工厂的类图相对比较复杂,不过本质就是表达了,客户端依赖几个抽象,而不是这些抽象的具体实现的依赖倒置关系。为了便于描述,下面将系列中包含的类型称为产品,即下图中有两种产品A和B,以及两个系列1和2。
模式的参与者如下:
1、抽象工厂,提供了创建系列中各个产品的抽象方法——AbstractFactory;
2、具体的工厂实现,用来创建某一个系列的产品——Factory1、Factory2;
3、产品的抽象——IProductA、IProductB;
4、每个系列的产品具体实现——ProductA1、ProductA2、ProductB1、ProductB2;
5、客户端类,只依赖于1和3的抽象——Client。
示例
假设我们有一个网页,需要提供两种风格的头和尾(比如男性版和女性版)。这两种风格的头尾当然不能混用,否则效果将是惨不忍睹。所以要嘛使用风格1,要嘛使用风格2,两种风格构成了两个系列,页面头部和尾部构成了系列中的两个产品。下面用抽象工厂实现。
1、定义页面头部的接口IHeader。
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 头部
7: /// </summary>
8: public interface IHeader
9: {
10: string GetHeaderContent();
11: }
12: }
13:
2、提供IHeader接口的两个实现。
StyleAHeader:
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 风格A的头部
7: /// </summary>
8: public class StyleAHeader : IHeader
9: {
10: public string GetHeaderContent()
11: {
12: return "这是风格A的头部。。。";
13: }
14: }
15: }
16:
StyleBHeader:
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 风格B的头部
7: /// </summary>
8: public class StyleBHeader : IHeader
9: {
10: public string GetHeaderContent()
11: {
12: return "这是风格B的头部。。。";
13: }
14: }
15: }
16:
3、定义页面尾部的接口IFooter。
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 尾部
7: /// </summary>
8: public interface IFooter
9: {
10: string GetFooterContent();
11: }
12: }
13:
4、提供IFooter接口的两个实现。
StyleAFooter:
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 风格A的尾部
7: /// </summary>
8: public class StyleAFooter : IFooter
9: {
10: public string GetFooterContent()
11: {
12: return "这是风格A的尾部。。。";
13: }
14: }
15: }
16:
StyleBFooter:
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 风格B的尾部
7: /// </summary>
8: public class StyleBFooter : IFooter
9: {
10: public string GetFooterContent()
11: {
12: return "这是风格B的尾部。。。";
13: }
14: }
15: }
16:
5、实现抽象工厂AbstractStyleFactory,这里只做演示,实际应用中应该用技术手段去除生成工厂时的分支判断。
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 风格工厂接口
7: /// </summary>
8: public abstract class AbstractStyleFactory
9: {
10: //此处的值可能来自配置文件
11: private static string styleName = "A";
12:
13: private static AbstractStyleFactory instance;
14:
15: public static AbstractStyleFactory Instance
16: {
17: get
18: {
19: if (instance == null)
20: {
21: //此处可能会用到发射等技术
22: if (styleName == "A")
23: instance = new StyleAFactory();
24: else
25: instance = new StyleBFactory();
26: }
27: return instance;
28: }
29: }
30:
31: public abstract IHeader CreateHeader();
32: public abstract IFooter CreateFooter();
33: }
34: }
35:
6、具体工厂实现。
StyleAFactory:
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 风格A的工厂实现
7: /// </summary>
8: public class StyleAFactory : AbstractStyleFactory
9: {
10: public override IHeader CreateHeader()
11: {
12: return new StyleAHeader();
13: }
14:
15: public override IFooter CreateFooter()
16: {
17: return new StyleAFooter();
18: }
19: }
20: }
21:
StyleBFactory:
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: /// <summary>
6: /// 风格B的工厂实现
7: /// </summary>
8: public class StyleBFactory : AbstractStyleFactory
9: {
10: public override IHeader CreateHeader()
11: {
12: return new StyleBHeader();
13: }
14:
15: public override IFooter CreateFooter()
16: {
17: return new StyleBFooter();
18: }
19: }
20: }
21:
7、客户端代码。
1: using System;
2:
3: namespace DesignPatterns.AbstractFactory
4: {
5: class Program
6: {
7: static void Main(string[] args)
8: {
9: //获得工厂对象
10: AbstractStyleFactory factory = AbstractStyleFactory.Instance;
11:
12: //创建具体的对象
13: IHeader header = factory.CreateHeader();
14: IFooter footer = factory.CreateFooter();
15:
16: //输出
17: Console.WriteLine(header.GetHeaderContent());
18: Console.WriteLine("内容");
19: Console.WriteLine(footer.GetFooterContent());
20:
21: Console.WriteLine("按任意键结束...");
22: Console.ReadKey();
23: }
24: }
25: }
26:
8、运行查看结果。
上面的例子比较简单,博文http://www.cnblogs.com/terrylee/archive/2005/12/13/295965.html,提供了更加贴近实际的一个示例,可以参考。