2012年9月5日星期三

温故知新(4)抽象工厂模式

温故知新(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、运行查看结果。

image

上面的例子比较简单,博文http://www.cnblogs.com/terrylee/archive/2005/12/13/295965.html,提供了更加贴近实际的一个示例,可以参考。


TAG: