工厂模式之抽象工厂

主要参考《大话设计模式》css

1. 引入

  前面介绍的工厂方法模式中考虑的是一类产品的生产,如畜牧场养动物、电视机厂生产电视等,然而,现实生活中,许多工厂是综合型工厂,可以生产各种产品,如大学包括各个系。sql

2. 定义

  抽象工厂模式,为建立一组相关或相互依赖的对象提供一个接口,且无需指定它们的具体类。是全部形态的工厂模式中最为抽象和最具通常性的一种形态。数据库

3. 场景实现

3.1 场景描述 

  在框架开发中,对于同一个ORM,假如刚开始开发时使用SQL Server数据库,可是也但愿可以链接Access数据库,或其余的数据库(如MySql、Oracle等)。SQL Server在.net中使用的System.Data.SqlClient命名空间下的SqlConnection、SqlCommand、SqlParameter、SqlDataReader、SqlDataAdapter,而Access要用System.Data.Olede命名空间下的相应对象,咱们不可能修改命名空间,或者从新写相同的业务代码只是修改与数据库相关的代码,这就是两倍的工做量。于是,针对相似问题,能够采用抽象工厂模式解决。设计模式

  好比,如今要在业务逻辑代码类似的状况下,将SqlServer数据库改成使用Access数据库。 以“新增用户”和“获取用户”为例给出最基本的数据库访问程序。框架

3.2 最基本的数据访问程序

  class User
    {
        private int _id;
        public int ID
        {
            get { return _id;}
            set { _id = value; }
        }
        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
    }
  class SqlServer
    {
        public void insert(User user)
        {
            Console.WriteLine("在sqlserver中为User表添加一条记录");
        }
        public void select(int id)
        {
            Console.WriteLine("在sqlserver中根据用户id查找用户");
        }
    }
  static void Main(string[] args)
        {
            User user = new User();
            SqlServer sql = new SqlServer();
            sql.insert(user);
            sql.select(1);
            Console.Read();
        }

运行结果以下:sqlserver

  上述实现中,没法灵活的把sqlserver数据库替换成其余数据库,缘由就是SqlServer sql = new SqlServer()使得sql对象被框死在Sqlserver上,若是此处是灵活的(多态的)应用,在执行sql.insert(user)时,不须要关注数据库究竟是sqlserver仍是access,所以,咱们能够采用工厂方法模式进行封装。工厂方法模式是定义一个用于建立对象的接口,让子类决定实例化哪一个类。this

3.3 使用工厂方法模式的数据访问程序

3.3.1 UML图

 

3.3.2 代码实现

class User
    {
        private int _id;
        public int ID
        {
            get { return _id;}
            set { this._id = value; }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set { this._name = value; }
        }
    }
interface IUser
    {
        void Insert(User user);
        User GeUser(int id);
    }
 class SqlserverUser:IUser
    {
        public void Insert(User user)
        {
            Console.WriteLine("在Sqlserver中新增一个用户");
        }
       
        public User GeUser(int id)
        {
            Console.WriteLine("在sqlserver中获取一个用户");
            return null;
        }
    }
class AccessUser:IUser
    {
        public void Insert(User user)
        {
            Console.WriteLine("在Access中新增一个用户");
        }
       
        public User GeUser(int id)
        {
            Console.WriteLine("在Access中获取一个用户");
            return null;
        }
    }
  interface IFactory { IUser CreateUser(); } class SqlserverFactory:IFactory
    {
        public IUser CreateUser()
        {
            return new SqlserverUser();
        }
    }
class AccessFactory:IFactory
    {
        public IUser CreateUser()
        {
            return new AccessUser();
        }
    }
static void Main(string[] args)
        {
            User user=new User();
            IFactory factory=new SqlserverFactory();
            IUser sqlUser = factory.CreateUser();
            sqlUser.Insert(user);
            sqlUser.GeUser(1);
            Console.WriteLine("Hello World!");
        }

  上述为使用工厂方法模式实现不一样数据库中Insert、GetUser方法的实现,该实现中抽象接口与接口相关联,而不是与具体的类耦合,对代码进行了解耦,极大增长了代码的灵活性。在main方法中只须要根据本身的需求生成数据库实例便可,加入须要使用access数据库,只需main中修改成如下语句便可:spa

IFactory factory=new AccessFactory();

3.4 使用抽象工厂实现

  上述用工厂方法实现不一样数据库新增或获取User表数据,虽然实现了具体类与类之间的耦合,但一个数据库中会存在不少表,好比Department表,若是须要获取Department数据,则须要新增一个Department、ServerDepartment、AccessDepartment 3个类并更改IFactory、SqlServerFactory、AccssFactory操作系统

3.4.1 UML图

  其中,IDepartment接口,用于客户端访问,解除具体数据库访问的耦合。.net

3.4.2 代码实现  

//IDepartment接口,用于客户端访问,解除具体数据库访问的耦合。
interface
IDepartment { void Insert(Department depement); User GeUser(int id); } class Department { private int _id; public int ID { get { return _id;} set { this._id = value; } } private string _name; public string Name { get { return _name; } set { this._name = value; } } }
//SqlserverDepartment类,用于访问sqlserver的Department
class SqlserverDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在Sqlserver中新增一个部门"); } public Department GetDepartment(int id) { Console.WriteLine("在sqlserver中获取一个部门"); return null; } }
//AccessDepartment类,用于访问access数据库的Department
class AccessDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在Access中新增一个部门"); } public Department GetDepartment(int id) { Console.WriteLine("在Access中获取一个部门"); return null; } }
 interface IFactory
    {
        IUser CreateUser();
        IDepartment CreateDepartment();
    } 
// AccessFactory,实现IFactory接口,实例化AccessUser和AccessDepartment
class AccessFactory:IFactory
    {
        public IUser CreateUser()
        {
            return new AccessUser();
        }

        public IDepartment CreateDepartment()
        {
            return new AccessDepartment();
        }
    }
// SqlserverFactory类,实现IFactory接口,实例化SqlserverUser和SqlserverDepartment
class SqlserverFactory:IFactory
    {
        public IUser CreateUser()
        {
            return new SqlserverUser();
        }

        public IDepartment CreateDepartment()
        {
            return  new SqlserverDepartment();
        }
    }
static void Main(string[] args)
        {
            User user=new User();
            Department dep=new Department();
            //IFactory factory=new SqlserverFactory();
            IFactory factory=new AccessFactory();
            IUser sqlUser = factory.CreateUser();
            sqlUser.Insert(user);
            sqlUser.GeUser(1);

            IDepartment id = factory.CreateDepartment();
            id.Insert(dep);
            id.GetDepartment(1);
            Console.WriteLine("Hello World!");
        }

  客户端只需肯定实例化哪一个数据库访问对象给factory。

  只有一个User类和User操做类的时候,只须要工厂方法模式,但因为数据库中会有不少表,sqlserver和access又是两个不一样的分类,所以,该问题中涉及多个产品系列的问题,对其实现,采用了抽象工厂模式。

4. 抽象工厂模式UML图

 

  上图中,AbstractProductA和AbstractProductB是两个抽象产品,对应于第3.4节场景分析中的User类和Department类,它们又拥有本身不一样的实现,所以,ProductA一、ProductA一、ProductB一、ProductB2就是对两个抽象产品具体分类的实现,分别表明SqlserverUser、AccessUser、SqlserverDepartment、AccessDepartment。.IFactory做为一个抽象工厂接口,应该包含实现建立产品的方法(如:CreateSqlServer,CreateAccess).而CreateFactory1和CreateFactory2则表明具体的工厂(如:SqlServerFactory,AccessFactory)。一般,会在客户端建立具体工厂类的实例,这个工厂再建立具备特定实现的产品对象,即为建立不一样的产品对象,客户端应使用不一样的具体工厂。

5. 其余应用场景

  例如一个应用,须要在三个不一样平台上运行:Windows、Linux、Android等,三个不一样操做系统上的软件功能、应用逻辑、UI都应该是很是相似,惟一不一样的是调用不一样的工厂方法,由不一样的产品类去处理与操做系统交互的信息。

 6. 总结

   抽象工厂模式的优势及缺点:

  优势:

  • (1)易于交换产品系列(如:上例中,使用SqlServer数据库仍是Access数据库只需改变IFactury factory = new AccessFactory();/便可),只需改变具体工厂便可使用不一样的产品配置
  • (2)具体的建立实例过程与客户端分离。客户端是经过抽象接口操做实例,产品的具体类名也被具体工厂的实现分离,不会出如今客户代码中。

   缺点:

  产品的扩展困难,如上例产品中须要添加一张表Project,此时须要增长IProject 、SqlServerProject、AccessProject,并更改IFactory、SqlServerFactory、AccssFactory,改动较大。所以,在使用抽象工厂模式时,产品的结构等级结构划分很是重要。

相关文章
相关标签/搜索