创建型模式:抽象工厂(Abstract Factory)

Posted wgx0428

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型模式:抽象工厂(Abstract Factory)相关的知识,希望对你有一定的参考价值。

定义

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

UML类图

技术图片

工厂方法模式切换数据库

namespace 抽象工厂02
{
    /// <summary>
    /// 抽象产品
    /// </summary>
    public interface IUser
    {
        User GetUser(int id);
        void InsertUser(User entity);
    }
}
namespace 抽象工厂02
{
    /// <summary>
    /// 用户表
    /// </summary>
    public class User
    {
        public int ID { get; set; }

        public string Name { get; set; }
    }
}
using System;

namespace 抽象工厂02
{
    /// <summary>
    /// 具体产品
    /// </summary>
    public class SqlServerUser : IUser
    {
        public User GetUser(int id)
        {
            Console.WriteLine("在SQL Server中根据ID得到User表中一条记录");
            return null;
        }

        public void InsertUser(User entity)
        {
            Console.WriteLine("在SQL Server中给User表中增加一条记录");
        }
    }
}
namespace 抽象工厂02
{
    /// <summary>
    /// 抽象工厂
    /// </summary>
    public interface IFactory
    {
        IUser CreateUser();
    }
}
namespace 抽象工厂02
{
    /// <summary>
    /// SqlServer方式具体工厂
    /// </summary>
    public class SqlServerFactory : IFactory
    {
        public IUser CreateUser()
        {
            return new SqlServerUser();
        }
    }
}
using System;

namespace 抽象工厂02
{
    /// <summary>
    /// Access方式访问数据--具体产品
    /// </summary>
    public class AccessUser : IUser
    {
        public User GetUser(int id)
        {
            Console.WriteLine("在Access中根据ID得到User表中一条记录");
            return null;
        }

        public void InsertUser(User entity)
        {
            Console.WriteLine("在Access中给User表中增加一条记录");
        }
    }
}
namespace 抽象工厂02
{
    /// <summary>
    /// Access方式的工厂
    /// </summary>
    public class AccessFactory : IFactory
    {
        public IUser CreateUser()
        {
            return new AccessUser();
        }
    }
}
using System;

namespace 抽象工厂02
{
    /// <summary>
    /// 运用工厂方法模式实现(不同数据库的快速切换)
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //1.创建具体工厂
            IFactory factory = new SqlServerFactory(); //如果用Access数据库只需要将SqlServerFactory改为AccessFactory就可以了

            //2.根据工厂生产具体
            IUser user= factory.CreateUser();

            user.InsertUser(new User() { Name="成吉思汗" });
            user.GetUser(3);

            Console.ReadKey();
        }
    }
}

抽象工厂切换数据库,新增一个产品部门

namespace 抽象工厂03
{
    /// <summary>
    /// 部门表
    /// </summary>
    public class Department
    {
        public int ID { get; set; }
        /// <summary>
        /// 部门名称
        /// </summary>
        public string Name { get; set; }
    }
}
namespace 抽象工厂03
{
    /// <summary>
    /// 部门抽象接口
    /// </summary>
    public interface IDepartment
    {
        Department GetDepartment(int id);

        void InsertDepartment(Department entity);
    }
}
using System;

namespace 抽象工厂03
{
    public class AccessDepartment : IDepartment
    {
        public Department GetDepartment(int id)
        {
            Console.WriteLine("在Access中根据ID得到Department表中一条记录");
            return null;
        }

        public void InsertDepartment(Department entity)
        {
            Console.WriteLine("在Access中给Department表中增加一条记录");
        }
    }
}
namespace 抽象工厂03
{
    /// <summary>
    /// 抽象工厂 (应该包含所有产品创建的抽象方法)
    /// </summary>
    public interface IFactory
    {
        IUser CreateUser();

        IDepartment CreateDepartment();
        
    }
}
namespace 抽象工厂03
{
    /// <summary>
    /// Access方式的工厂(具体工厂创建具有特定实现的产品对象)
    /// </summary>
    public class AccessFactory : IFactory
    {
        public IDepartment CreateDepartment()
        {
            return new AccessDepartment();
        }

        public IUser CreateUser()
        {
            return new AccessUser();
        }
    }
}

using System;

namespace 抽象工厂03
{
    /// <summary>
    /// SqlServer部门产品
    /// </summary>
    public class SqlServerDepartment : IDepartment
    {
        public Department GetDepartment(int id)
        {
            Console.WriteLine("在SqlServer中根据ID得到Department表中一条记录");
            return null;
        }

        public void InsertDepartment(Department entity)
        {
            Console.WriteLine("在SqlServer中给Department表中增加一条记录");
        }
    }
}
namespace 抽象工厂03
{
    /// <summary>
    /// SqlServer方式具体工厂
    /// </summary>
    public class SqlServerFactory : IFactory
    {
        public IDepartment CreateDepartment()
        {
            return new SqlServerDepartment();
        }

        public IUser CreateUser()
        {
            return new SqlServerUser();
        }
    }
}
using System;

namespace 抽象工厂03
{
    /// <summary>
    /// 运用抽象工厂模式实现(不同数据库的快速切换)
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //1.创建具体工厂
            IFactory factory = new AccessFactory();

            //2.通过工厂生成具体产品
            IDepartment department = factory.CreateDepartment();

            //3.根据id获取部门
            department.GetDepartment(3);

            Console.ReadKey();
        }
    }
}

抽象工厂第二版

  • 去掉具体的AccessFactory和SqlServerFactory,增加一个工厂类DataAccess
namespace 抽象工厂04
{
    /// <summary>
    /// 增加工厂类改造抽象工厂
    /// </summary>
    public class DataAccess
    {
        private static readonly string db = "SqlServer";
        //private static readonly string db = "Access";

        public static IUser CreateUser()
        {
            IUser result = null;
            switch (db)
            {
                case "SqlServer":
                    result = new SqlServerUser();
                    break;
                case "Access":
                    result = new AccessUser();
                    break;
                default:
                    break;
            }
            return result;
        }

        public static IDepartment CreateDepartment()
        {
            IDepartment result = null;
            switch (db)
            {
                case "SqlServer":
                    result = new SqlServerDepartment();
                    break;
                case "Access":
                    result = new AccessDepartment();
                    break;
                default:
                    break;
            }
            return result;
        }
    }
}
namespace 抽象工厂04
{
    /// <summary>
    /// 用简单工厂改造抽象工厂
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            IUser user = DataAccess.CreateUser();   //直接得到数据库实例,不存在任何依赖
            user.GetUser(3);

            IDepartment deparment = DataAccess.CreateDepartment();
            deparment.InsertDepartment(new Department() { Name="研发部" });

        }
    }
}

抽象工厂第三版优化

  • 使用反射的方式加配置文件的方式可做到动态切换数据库
  • 添加配置文件App.config
    技术图片
using System.Configuration;
using System.Reflection;
namespace 抽象工厂05
{
    /// <summary>
    /// 通过反射创建对象
    /// </summary>
    public class DataAccess
    {
        private static readonly string AssemblyName = "抽象工厂05";
        private static readonly string db = ConfigurationManager.AppSettings["db"];

        /// <summary>
        /// 创建用户抽象产品的工厂方法
        /// </summary>
        /// <returns></returns>
        public static IUser CreateUser()
        {
            string className= AssemblyName + "." + db + "User";
            
            return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
        }

        /// <summary>
        /// 创建部门抽象产品的工厂方法
        /// </summary>
        /// <returns></returns>
        public static IDepartment CreateDepartment()
        {
            string className = AssemblyName + "." + db + "Department";

            return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
        }
    }
}

using System;
namespace 抽象工厂05
{
    /// <summary>
    /// 反射+抽象工厂方式实现数据访问
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            IUser iUser = DataAccess.CreateUser();
            iUser.InsertUser(new User() { Name="赵一曼" });

            IDepartment iDepartment = DataAccess.CreateDepartment();
            iDepartment.GetDepartment(3);

            Console.ReadKey();
        }
    }
}

优点

  • 易于交换产品系列,由于具体工厂类在每一个应用中只需要在初始化的时候出现一次,这就使得改变一个具体应用工厂变得非常容易。只需要改变具体工厂即可改变不同的产品配置。
  • 它让具体的创建实例过程与客户端分类,客户端是通过它们的抽象接口操作实例,产品的具体类名也被具体工厂的实现分离。不会出现在客户代码中。
  • 很好的遵循了开放-封闭原则。对于新添加产品只需要在工厂方法里面添加新的工厂就可以了。

缺点

  • 标准的抽象工厂需要额外增加很多工厂类,但是用简单工厂优化后就相对好很多。

以上是关于创建型模式:抽象工厂(Abstract Factory)的主要内容,如果未能解决你的问题,请参考以下文章

创建型模式:抽象工厂(Abstract Factory)

002-创建型-02-抽象工厂模式(Abstract Factory)

设计模式从青铜到王者第七篇:创建型模式之抽象工厂模式(Abstract Factory)

抽象工厂模式(Abstract Factory)

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory Pattern)