抽象工厂模式(Abstract Factory )


概述
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象的创建方法(
new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。

意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

例子
1.某游戏的场景。
2.某款汽车的外观风格。
3.某软件的外观皮肤。

UML类图
                      


代码:对应UML类图
首先,创建抽象工厂类,抽象产品A类,抽象产品B类。面向接口(抽象)编程
 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3
 4    /// <summary>
 5    /// 抽象工厂
 6    /// </summary>

 7    public abstract class AbstractFactory
 8    {
 9        /// <summary>
10        /// 创建产品A
11        /// </summary>
12        /// <returns></returns>

13        public abstract AbstractProductA CreateProductA();
14
15        /// <summary>
16        /// 创建产品B
17        /// </summary>
18        /// <returns></returns>

19        public abstract AbstractProductB CreateProductB();
20    }

21}

1namespace DesignPatterns.AbstractFactory.UMLCode
2{
3    /// <summary>
4    /// 抽象产品A
5    /// </summary>

6    public abstract class AbstractProductA
7    {
8    }

9}

 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 抽象产品B
 5    /// </summary>

 6    public abstract class AbstractProductB
 7    {
 8        /// <summary>
 9        /// 产品交互
10        /// </summary>
11        /// <param name="abstractProductA"></param>

12        public abstract void Interact(AbstractProductA abstractProductA);
13    }

14}

接着,实现一套具体的工厂类,具体的产品A类,具体的产品B类,分别继承上述三个抽象类。
 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 具体工厂1
 5    /// </summary>

 6    public class ConcreteFactory1:AbstractFactory
 7    {
 8        /// <summary>
 9        /// 覆写抽象方法,创建具体产品A
10        /// </summary>
11        /// <returns></returns>

12        public override AbstractProductA CreateProductA()
13        {
14            return new ProductA1();
15        }

16
17        /// <summary>
18        /// 覆写抽象方法,创建具体产品B
19        /// </summary>
20        /// <returns></returns>

21        public override AbstractProductB CreateProductB()
22        {
23            return new ProductB1();
24        }

25    }

26}

1namespace DesignPatterns.AbstractFactory.UMLCode
2{
3    /// <summary>
4    /// 具体产品A1
5    /// </summary>

6    public class ProductA1:AbstractProductA
7    {
8    }

9}

 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 具体产品B1
 5    /// </summary>

 6    public class ProductB1:AbstractProductB
 7    {
 8        /// <summary>
 9        /// 产品交互
10        /// </summary>
11        /// <param name="abstractProductA"></param>

12        public override void Interact(AbstractProductA abstractProductA)
13        {
14            Console.WriteLine(this.GetType().Name + " interact with :" + abstractProductA.GetType().Name);
15        }

16    }

17}

最后,客户程序可以通过创建具体的工厂来自动生产相应的产品。但是,这样的话客户端就对具体的工厂产生了依赖,当新增加一套产品时,需要修改客户端的产生具体工厂的代码。
 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 客户端类
 5    /// </summary>

 6    class Client
 7    {
 8        private AbstractProductA abstractProductA;
 9        private AbstractProductB bbstractProductB;
10
11        /// <summary>
12        /// 构造函数
13        /// </summary>
14        /// <param name="factory"></param>

15        public Client(AbstractFactory factory)
16        {
17            this.abstractProductA = factory.CreateProductA();
18            this.bbstractProductB = factory.CreateProductB();
19        }

20
21        /// <summary>
22        /// 运行
23        /// </summary>

24        private void Run()
25        {
26            this.bbstractProductB.Interact(this.abstractProductA);
27        }

28
29        /// <summary>
30        /// 主程序
31        /// </summary>

32        public static void Main()
33        {
34            // 方式1
35            // 直接依赖具体工厂1
36            AbstractFactory factory = new ConcreteFactory1();
37
38            new Client(factory).Run();
39            Console.Read();
40        }

41    }

42}

现在新增一套产品(具体工厂2,具体产品A2,具体产品B2)
 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 具体工厂2
 5    /// </summary>

 6    public class ConcreteFactory2:AbstractFactory
 7    {
 8        public override AbstractProductA CreateProductA()
 9        {
10            return new ProductA2();
11        }

12
13        public override AbstractProductB CreateProductB()
14        {
15            return new ProductB2();
16        }

17    }

18}

 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 具体产品A2
 5    /// </summary>

 6    class ProductA2:AbstractProductA
 7    {
 8    }

 9}

10

 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 具体产品B2
 5    /// </summary>

 6    class ProductB2:AbstractProductB
 7    {
 8        public override void Interact(AbstractProductA abstractProductA)
 9        {
10            Console.WriteLine(this.GetType().Name + " is interact with :" + abstractProductA.GetType().Name);
11        }

12    }

13}

这时客户端的程序必须修改为

 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 客户端类
 5    /// </summary>

 6    class Client
 7    {
 8        private AbstractProductA abstractProductA;
 9        private AbstractProductB bbstractProductB;
10
11        /// <summary>
12        /// 构造函数
13        /// </summary>
14        /// <param name="factory"></param>

15        public Client(AbstractFactory factory)
16        {
17            this.abstractProductA = factory.CreateProductA();
18            this.bbstractProductB = factory.CreateProductB();
19        }

20
21        /// <summary>
22        /// 运行
23        /// </summary>

24        private void Run()
25        {
26            this.bbstractProductB.Interact(this.abstractProductA);
27        }

28
29        /// <summary>
30        /// 主程序
31        /// </summary>

32        public static void Main()
33        {
34            // 方式1
35            //// 直接依赖具体工厂1
36            //AbstractFactory factory = new ConcreteFactory1();
37
38            //new Client(factory).Run();
39            //Console.Read();
40
41            // 当新增产品(更换系列产品)时,必须将代码修改为如下,又对具体的工厂2产生了直接依赖
42            AbstractFactory factory = new ConcreteFactory2();
43
44            new Client(factory).Run();
45            Console.Read();
46        }

47    }

48}

下面将通过反射机制将这种对变化点的依赖转移到配置文件,这样,可以对变化做出最快反应。

 1namespace DesignPatterns.AbstractFactory.UMLCode
 2{
 3    /// <summary>
 4    /// 客户端类
 5    /// </summary>

 6    class Client
 7    {
 8        private AbstractProductA abstractProductA;
 9        private AbstractProductB bbstractProductB;
10
11        /// <summary>
12        /// 构造函数
13        /// </summary>
14        /// <param name="factory"></param>

15        public Client(AbstractFactory factory)
16        {
17            this.abstractProductA = factory.CreateProductA();
18            this.bbstractProductB = factory.CreateProductB();
19        }

20
21        /// <summary>
22        /// 运行
23        /// </summary>

24        private void Run()
25        {
26            this.bbstractProductB.Interact(this.abstractProductA);
27        }

28
29        /// <summary>
30        /// 主程序
31        /// </summary>

32        public static void Main()
33        {
34            // 方式1
35            //// 直接依赖具体工厂1
36            //AbstractFactory factory = new ConcreteFactory1();
37
38            //new Client(factory).Run();
39            //Console.Read();
40
41            //// 当新增产品(更换系列产品)时,必须将代码修改为如下,又对具体的工厂2产生了直接依赖
42            //AbstractFactory factory = new ConcreteFactory2();
43
44            //new Client(factory).Run();
45            //Console.Read();
46
47            // 方式2:通过反射机制,将具体工厂的创建工作(变化点),推迟到配置文件,
48            // 即将变换点封装在配置文件,这样对于客户系列对象的变化,将可以做出最快的反应。
49            // 当需要更换系列产品时,直接修改配置文件中相应的factoryClassName和factoryAssemblyName的值。
50
51            // 反射实例话方式: Assembly.Load("AssemblyName").CreateInstance("ClassName")
52            string factoryClassName = "DesignPatterns.AbstractFactory.UMLCode.ConcreteFactory1";
53            string factoryAssemblyName = "DesignPatterns";
54            Assembly assembly = Assembly.Load(factoryAssemblyName);
55            AbstractFactory factory = (AbstractFactory)assembly.CreateInstance(factoryClassName);
56
57            new Client(factory).Run();
58            Console.Read();
59        }

60    }

61}


代码:完整例子
  实现数据库访问层的切换,以ORACLE和SQLSERVER数据库为例.
1.新建四个项目:AbstractDAL(抽象数据访问层),SqlDAL(Sql数据访问层),OracleDAL(Oracle数据访问层),WebSite(站点)。
 

2.在项目AbstractDAL下,新建抽象工厂类和抽象订单类:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5using System.Reflection;
 6using System.Configuration;
 7
 8namespace AbstractDAL
 9{
10    /// <summary>
11    /// 抽象工厂
12    /// </summary>

13    public abstract class Factory
14    {        
15        public abstract Order CreateOrder();
16    }

17}

18

 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace AbstractDAL
 6{
 7    /// <summary>
 8    /// 抽象的订单
 9    /// </summary>

10    public abstract class Order
11    {
12        public abstract string Name
13        {
14            get;
15        }

16    }

17}

18

2.在项目SqlDAL下,新建针对Sql的具体工厂类和和具体订单类:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace SqlDAL
 6{
 7    /// <summary>
 8    /// Sql 数据库工厂
 9    /// </summary>

10    public class Factory:AbstractDAL.Factory
11    {
12        public override AbstractDAL.Order CreateOrder()
13        {
14            return new Order();
15        }

16
17    }

18}

19

 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace SqlDAL
 6{
 7    /// <summary>
 8    /// Sql Order
 9    /// </summary>

10    public class Order:AbstractDAL.Order
11    {
12        public override string Name
13        {
14            get
15            {
16                // 做一些数据库增删改操作
17                return "SqlOrderName";
18            }

19        }

20    }

21}

22

3.在项目OracleDAL下,新建针对Oracle的具体工厂类和和具体订单类:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace OracleDAL
 6{
 7    /// <summary>
 8    /// Oracle 数据库工厂
 9    /// </summary>

10    public class Factory:AbstractDAL.Factory
11    {
12        public override AbstractDAL.Order CreateOrder()
13        {
14            return new Order();
15        }

16
17    }

18}

19

 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace OracleDAL
 6{
 7    /// <summary>
 8    /// Oracle Order
 9    /// </summary>

10    public class Order:AbstractDAL.Order
11    {
12        public override string Name
13        {
14            get
15            {
16                // 做一些数据库增删改操作
17                return "OracleOrderName";
18            }

19        }

20    }

21}

22

4.Web.config相应配置
1
2  <appSettings>
3    <add key="factoryClassName" value="SqlDAL.Factory"/>
4    <add key="factoryAssemblyName" value="SqlDAL"/>
5  </appSettings>
6  

5.在WebSite下新建类:DALFactory.cs,封装从Web.config中读取具体的数据库工厂配置。
 1using System;
 2using System.Data;
 3using System.Configuration;
 4using System.Web;
 5using System.Web.Security;
 6using System.Web.UI;
 7using System.Web.UI.WebControls;
 8using System.Web.UI.WebControls.WebParts;
 9using System.Web.UI.HtmlControls;
10
11using AbstractDAL;
12using System.Reflection;
13
14namespace WebSite
15{
16    /// <summary>
17    /// 数据访问层工厂,单件模式
18    /// </summary>

19    public class DALFactory
20    {
21        private static Factory instance;
22        public static Factory Instance
23        {
24            get
25            {
26                if (instance == null)
27                {
28                    string factoryAssemblyName = ConfigurationManager.AppSettings["factoryAssemblyName"];
29                    string factoryClassName = ConfigurationManager.AppSettings["factoryClassName"];
30                    Assembly assembly = Assembly.Load(factoryAssemblyName);
31                    instance = (Factory)assembly.CreateInstance(factoryClassName);
32                }

33                return instance;
34            }

35        }

36
37    }

38}

39

6.客户端Aspx.cs页面
 1using System;
 2using System.Data;
 3using System.Configuration;
 4using System.Collections;
 5using System.Web;
 6using System.Web.Security;
 7using System.Web.UI;
 8using System.Web.UI.WebControls;
 9using System.Web.UI.WebControls.WebParts;
10using System.Web.UI.HtmlControls;
11
12using AbstractDAL;
13using System.Reflection;
14
15namespace WebSite
16{
17    public partial class AbstractFactory : System.Web.UI.Page
18    {
19        /// <summary>
20        /// 加载
21        /// </summary>
22        /// <param name="sender"></param>
23        /// <param name="e"></param>

24        protected void Page_Load(object sender, EventArgs e)
25        {
26            // 获取数据库工厂,并通过其产生订单类
27            Factory factory = DALFactory.Instance;
28            Order order = factory.CreateOrder();
29
30            // 调用Order类的提供的接口
31            this.Response.Write(order.Name);
32        }

33    }

34}

35


总结
抽象工厂解决的是系列易变对象的创建问题。

 源代码:[下载]

参考
1. 【dofactory】ttp://www.dofactory.com/Patterns/Patterns.aspx#list
2. 【Terrylee】http://www.cnblogs.com/Terrylee/archive/2006/07/17/334911.html
3. 【卢振宇老师】http://zhenyulu.cnblogs.com/category/6930.html
posted on 2008-03-31 10:34  一麦  阅读(274)  评论(0编辑  收藏  举报