zoukankan      html  css  js  c++  java
  • 解读设计模式抽象工厂模式(AbstractFactory Pattern)

    一、模式描述
          我的程序中有需要一系列的对象,比如我们要吃一碗米饭(Rice),要喝一杯咖啡(Coffee)......,要想利用他们,我们就必须在程序中根据用户要求,然后一个个调用 new 操作符来生成他们,这样客户程序就要知道相应的类的信息,生成的代码显然不够灵活。那么我们可以在代码中不利用具体的类,而只是说明我们需要什么,然后就能够得到我们想要的对象呢? 
          这当然是可以的,根据GOF在《设计模式》一书里介绍,要创建对象这样的工作应该是属于创建型模式完成的。熟悉各种设计模式意图的朋友就会很快得出结论:“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类”,至少“无需指定它们具体的类”符合我们的要求。OK,这就是抽象工厂模式的意图。

    二、模式意图
          提供一个创建一系列相关或相互依赖对象的接口,而不需指定他们具体的类。

    三、模式UML图:                   
                 
    四、模式参与者
      抽象工厂(Abstract Factory)角色:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。 
      具体工厂(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
      抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
      具体产品(Concrete Product)角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。

    五、模式与反射
         利用设计模式可以使我们的代码更灵活,更容易扩展,更容易维护。各种面向对象的程序设计语言都提供了基本相同的机制:比如类、继承、派生、多态等等。但是又有各自的特色,C# 中的反射机制便是一个很重要的工具,好好地利用就可以在实际中发挥很大的作用。
         反射是.NET Framework中的一个非常重要的特性。相信绝大多数的朋友都对其有所了解或是已经熟练的应用这项技术。我们需要根据需求去动态的创建一对象的实例,在程序设计中,通常我们会为了解耦合,把接口的实现对象写入配置文件,让工厂自己去一个特定的地方(配置文件)找他应该要实例化的对象(接口的实现对象),通过这样来实现“依赖注入(Dependency Injection)”。
         本来“依赖注入”需要专门的IOC容器提供,比如Spring.net,Castle这类似的框架产品。而在抽象工厂模式的应用中显然没有这么麻烦,通常的实现就是使用.NET技术‘反射’就可以了。下面是反射的两种常见应用:
    应用一:
             Activator.CreateInstance("类型");
    应用二:
             Assembly.Load("程序集名称").CreateInstance("命名空间.类名称");


    六、抽象工厂的简单实现

    Entity Code
     1namespace DesignPattern.AbstractFactory
     2{
     3    /// <summary>
     4    /// 抽象产品角色
     5    /// </summary>

     6    public interface INews
     7    {
     8        void Insert(News news);
     9        News QueryById(int newsId);
    10    }

    11
    12    /// <summary>
    13    /// 具体产品角色
    14    /// </summary>

    15    public class NewsSql:INews
    16    {
    17        public void Insert(News news)
    18        {
    19            Console.WriteLine("插入新闻到SQL数据库");
    20        }

    21
    22        public News QueryById(int newsId)
    23        {
    24            return new News(1"Hello"" Hello C#!""beniao");
    25        }

    26    }

    27
    28    /// <summary>
    29    /// 具体产品角色
    30    /// </summary>

    31    public class NewsAccess : INews
    32    {
    33        public void Insert(News news)
    34        {
    35            Console.WriteLine("插入新闻到Access数据库");
    36        }

    37
    38        public News QueryById(int newsId)
    39        {
    40            return new News(1"Hello"" Hello C#!""beniao");
    41        }

    42    }

    43}
     1namespace DesignPattern.AbstractFactory
     2{
     3    /// <summary>
     4    /// 抽象产品角色
     5    /// </summary>

     6    public interface IUser
     7    {
     8        void Insert(User user);
     9        User QueryById(int userId);
    10    }

    11
    12    /// <summary>
    13    /// 具体产品角色
    14    /// </summary>

    15    public class UserSql:IUser
    16    {
    17        public void Insert(User user)
    18        {
    19            Console.WriteLine("Insert SQL OK!");
    20        }

    21
    22        public User QueryById(int userId)
    23        {
    24            return new User(1"beniao""22");
    25        }

    26    }

    27
    28    /// <summary>
    29    /// 具体产品角色
    30    /// </summary>

    31    public class UserAccess : IUser
    32    {
    33        public void Insert(User user)
    34        {
    35            Console.WriteLine("Insert Access OK!");
    36        }

    37
    38        public User QueryById(int userId)
    39        {
    40            return new User(2"beniao""23");
    41        }

    42    }

    43}
     1namespace DesignPattern.AbstractFactory
     2{
     3    /// <summary>
     4    /// 工厂角色(根据配置文件来确定创建何种对象)
     5    /// </summary>

     6    public class DataAccess
     7    {
     8        public static IUser CreateUser()
     9        {
    10            string obj = ConfigurationManager.AppSettings["usersql"];
    11            return (IUser)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
    12        }

    13
    14        public static INews CreateNews()
    15        {
    16            string obj = ConfigurationManager.AppSettings["newssql"];
    17            return (INews)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
    18        }

    19    }

    20***********************************************************************************
    21    /// <summary>
    22    /// 如果根据GOF的定义及UML图,此为抽象工厂角色
    23    /// </summary>

    24    public class Factory
    25    {
    26        public  virtual IUser CreateUser() 
    27        {
    28            return null;
    29        }

    30
    31        public  virtual INews CreateNews()
    32        {
    33            return null;
    34        }

    35    }

    36
    37    /// <summary>
    38    /// 具体的工厂角色
    39    /// </summary>

    40    public class SqlFactory:Factory
    41    {
    42        public override IUser CreateUser()
    43        {
    44            string obj = ConfigurationManager.AppSettings["usersql"];
    45            return (IUser)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
    46        }

    47
    48        public override INews CreateNews()
    49        {
    50            string obj = ConfigurationManager.AppSettings["newssql"];
    51            return (INews)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
    52        }

    53    }

    54
    55    /// <summary>
    56    /// 具体的工厂角色
    57    /// </summary>

    58    public class AccessFactory : Factory
    59    {
    60        public override IUser CreateUser()
    61        {
    62            string obj = ConfigurationManager.AppSettings["useracc"];
    63            return (IUser)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
    64        }

    65
    66        public override INews CreateNews()
    67        {
    68            string obj = ConfigurationManager.AppSettings["newsacc"];
    69            return (INews)Assembly.Load("DesignPattern.AbstractFactory").CreateInstance(obj);
    70        }
     
    71    }

    72}
     1namespace DesignPattern.AbstractFactory
     2{
     3    class Program
     4    {
     5        static void Main(string[] args)
     6        {
     7            IUser user = DataAccess.CreateUser();
     8            user.Insert(null);
     9
    10            INews news = DataAccess.CreateNews();
    11            news.Insert(null);
    12
    13            //******************GOF************************
    14
    15            Factory factory = new SqlFactory();
    16            factory.CreateNews().Insert(null);
    17            factory.CreateUser().Insert(null);
    18
    19            factory = new AccessFactory();
    20            factory.CreateNews().Insert(null);
    21            factory.CreateUser().Insert(null);
    22        }

    23    }

    24}

              
    七、.NET 2.0中的抽象工厂模式
         .NET 2.0相比.NET 1.1有很大的改进,就在ADO.NET上来说吧,提供了一套新的操作接口。下面我就简单的介绍下这套接口的设计,在System.Date下提供了IDbConnection IDbCommandIDbDataAdapter以及IDbTransaction这样一系列接口,通过ProviderFactory来完成具体实现对象的创建,这里就是抽象工厂模式的一个应用。示意性代码:

     1public IDbConnection CreateConnection()
     2{
     3    IDbConnection conn = null;
     4    try
     5    {
     6        conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[(int)_provider]);
     7    }

     8    catch(TargetInvocationException e)
     9    {
    10        throw new Exception(e.Message);
    11    }

    12    return conn;
    13}

    14
    15public IDbConnection CreateConnection(string connectionString)
    16{
    17    IDbConnection conn = null;
    18    object[] param ={ connectionString };
    19    try
    20    {
    21        conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[(int)_provider], param);
    22    }

    23    catch (TargetInvocationException e)
    24    {
    25        throw new Exception(e.Message);
    26    }

    27    return conn;
    28}

         在_connectionTypes数组里存放的是IDbConnection接口的具体实现类型,如下:

    private static Type[] _connectionTypes = new Type[] typeof(OleDbConnection), typeof(SqlConnection) };

    由于Command,DataAdapter等对象的代码都和上面很相似,这里就不作过多解释,我把代码贴到下面,有兴趣的看看:

    ProviderFactory

          关于.NET 2.0的这一知识点不了解的朋友可以下载Web Cast课程进行学习。本文就简单的介绍这些。

    七、.NET 2.0中的新ADO.NET操作接口应用示例
         建立一ASP.NET网站项目,在默认的Default.aspx里放置一个GridView控件便OK。这里以MSSQL 2000里的Northwind数据库作为示例数据库,查询出订单表的数据呈现在aspx页面上,进入后台代码文件(.cs文件):

     1public partial class _Default : System.Web.UI.Page 
     2{
     3    protected void Page_Load(object sender, EventArgs e)
     4    {
     5        string connectionString="Data Source=.;Initial Catalog=Northwind;user id=sa;password=;";
     6        string cmdText = "select * from orders";
     7
     8        ProviderFactory factory = new ProviderFactory(ProviderType.SqlClient);
     9        IDbConnection conn = factory.CreateConnection(connectionString);
    10        IDbDataAdapter sda = factory.CreateDataAdapter(cmdText, conn);
    11        DataSet ds = new DataSet();
    12        sda.Fill(ds);
    13        this.GridView1.DataSource = ds.Tables[0];
    14        this.GridView1.DataBind();
    15    }

    16}

          ProviderFactory担任着工厂的角色,负责创建如IDbConnection、IDbCommand等一系列的产品。如上,我们拿到了工厂角色,通过工厂角色的CreateConnection就创建到了一个基于抽象产品角色IDbConnection接口的实现对象(具体是什么实现对象我们暂不管)。
         .NET 2.0提供了这一套操作接口,对于程序实现上就更加灵活了,更是强调了使用“依赖接口/抽象编程”的思想。 

    示例程序代码下载
    注:转载请注明出处:http://beniao.cnblogs.com/ 或  http://www.cnblogs.com
    由于最近生病精神不振,文章介绍的不是很清楚,望大家体谅。

  • 相关阅读:
    (Vue中)cehart在同一个dom上画图图切换时饼图有折线图的坐标系
    linux(centos7)修改服务器时间
    centos6 yum源不能使用
    Linux 使用 history 来减少重复命令的几个实用技巧。
    7个Shell 拿来就用脚本实例!
    keepalived的配置解析&安装与爬坑
    linux最全命令使用手册
    linux各种误删文件恢复方法(经典强推)
    位运算符
    SQL 书写、执行顺序
  • 原文地址:https://www.cnblogs.com/beniao/p/1167987.html
Copyright © 2011-2022 走看看