zoukankan      html  css  js  c++  java
  • 抽象工厂模式(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
  • 相关阅读:
    关联分析(Association analysis)
    Django简介
    YAML快速入门
    YAML 在Python中的应用
    抓包工具、日誌抓取、弱網測試
    实现轮询
    Dubbo-从入门到深入
    Spring Boot
    小程序自动生成图片的标签
    小程序上传图片的大坑
  • 原文地址:https://www.cnblogs.com/im/p/1127817.html
Copyright © 2011-2022 走看看