主要参考《大话设计模式》css
前面介绍的工厂方法模式中考虑的是一类产品的生产,如畜牧场养动物、电视机厂生产电视等,然而,现实生活中,许多工厂是综合型工厂,可以生产各种产品,如大学包括各个系。sql
抽象工厂模式,为建立一组相关或相互依赖的对象提供一个接口,且无需指定它们的具体类。是全部形态的工厂模式中最为抽象和最具通常性的一种形态。数据库
在框架开发中,对于同一个ORM,假如刚开始开发时使用SQL Server数据库,可是也但愿可以链接Access数据库,或其余的数据库(如MySql、Oracle等)。SQL Server在.net中使用的System.Data.SqlClient命名空间下的SqlConnection、SqlCommand、SqlParameter、SqlDataReader、SqlDataAdapter,而Access要用System.Data.Olede命名空间下的相应对象,咱们不可能修改命名空间,或者从新写相同的业务代码只是修改与数据库相关的代码,这就是两倍的工做量。于是,针对相似问题,能够采用抽象工厂模式解决。设计模式
好比,如今要在业务逻辑代码类似的状况下,将SqlServer数据库改成使用Access数据库。 以“新增用户”和“获取用户”为例给出最基本的数据库访问程序。框架
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
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();
上述用工厂方法实现不一样数据库新增或获取User表数据,虽然实现了具体类与类之间的耦合,但一个数据库中会存在不少表,好比Department表,若是须要获取Department数据,则须要新增一个Department、ServerDepartment、AccessDepartment 3个类并更改IFactory、SqlServerFactory、AccssFactory操作系统
其中,IDepartment接口,用于客户端访问,解除具体数据库访问的耦合。.net
//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又是两个不一样的分类,所以,该问题中涉及多个产品系列的问题,对其实现,采用了抽象工厂模式。
上图中,AbstractProductA和AbstractProductB是两个抽象产品,对应于第3.4节场景分析中的User类和Department类,它们又拥有本身不一样的实现,所以,ProductA一、ProductA一、ProductB一、ProductB2就是对两个抽象产品具体分类的实现,分别表明SqlserverUser、AccessUser、SqlserverDepartment、AccessDepartment。.IFactory做为一个抽象工厂接口,应该包含实现建立产品的方法(如:CreateSqlServer,CreateAccess).而CreateFactory1和CreateFactory2则表明具体的工厂(如:SqlServerFactory,AccessFactory)。一般,会在客户端建立具体工厂类的实例,这个工厂再建立具备特定实现的产品对象,即为建立不一样的产品对象,客户端应使用不一样的具体工厂。
例如一个应用,须要在三个不一样平台上运行:Windows、Linux、Android等,三个不一样操做系统上的软件功能、应用逻辑、UI都应该是很是相似,惟一不一样的是调用不一样的工厂方法,由不一样的产品类去处理与操做系统交互的信息。
抽象工厂模式的优势及缺点:
优势:
缺点:
产品的扩展困难,如上例产品中须要添加一张表Project,此时须要增长IProject 、SqlServerProject、AccessProject,并更改IFactory、SqlServerFactory、AccssFactory,改动较大。所以,在使用抽象工厂模式时,产品的结构等级结构划分很是重要。