简介
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
书中实例
最近,小菜的项目需要更换数据库,原来用SQL Server,现在只能用Access。庞大的任务量致使小菜又懵逼了。如何能让更换数据库这件事灵活且简单呢?大鸟给他支了一招——抽象工厂模式。
举例来说:“现在要求写出一段数据访问的代码。假设只有‘新增用户’和‘得到用户’两个字段和两个方法。对了,数据库中除了User表还需要再增加一个部门表,”例子如下:
抽象工厂模式实现程序
//用户表 class User { private int _id; private int ID { get { return _id; } set { _id = value;} } private string _name; public string Name { get { return _name; } set { _name = value; } } }
//SqlserverUser类 用于访问SQLServer的User class SqlserverUser : IUser { public void Insert(User user) { Console.WriteLine("在SQLServer中根据ID得到User表一条记录"); } public User GetUser(int id) { Console.WriteLine("在SQLServer中根据id得到User表一条记录"); return null; } }
//IUser接口 用于客户端的访问,解除与具体数据库访问的耦合 interface IUser { void Insert(User user); User GetUser(int id); }
//AccessUser类 用于访问Access的User class AccessUser : IUser { public void Insert(User user) { Console.WriteLine("在Access中给User表增加一条记录"); } public User GetUser(int id) { Console.WriteLine("在Access中根据ID得到User表一条记录"); return null; } }
//抽象工厂接口 定义一个创建访问User表对象的抽象工厂接口+Department interface IFactory { IUser CreateUser(); IDepartment CreateDepartment(); }
//SqlServerFactory类 实现IFactory接口,实例化SqlserverUser和SqlserverDepartment class SqlServerFactory : IFactory { public IUser CreateUser() { return new AccessUser(); } public IDepartment CreateDepartment() { return new SqlserverDepartment(); } }
//AccessFactory类 实现IFactory接口,实例化AccessUser和AccessDepartment class AccessFactory : IFactory { public IUser CreateUser() { return new AccessUser(); } public IDepartment CreateDepartment() { return new AccessDepartment(); } }
//部门表 class Department { private int _id; private int ID { get { return _id; } set { _id = value; } } private string _deptName; public string DeptName { get { return _deptName; } set { _deptName = value; } } }
//IDepartment接口 用于客户端访问,解除与具体数据库访问的耦合 interface IDepartment { void Insert(Department department); Department GetDepartment(int id); }
//SqlserverDepartment类 用于访问SQLServer的Department class SqlserverDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在SQLServer中给Department表增加一条记录"); } public Department GetDepartment(int id) { Console.WriteLine("在SQLServer中根据ID得到Department表一条记录"); return null; } }
//AccessDepartment类 用于访问Access的Department class AccessDepartment : IDepartment { public void Insert(Department department) { Console.WriteLine("在Access中给Department表增加一条记录"); } public Department GetDepartment(int id) { Console.WriteLine("在Access中根据ID得到Department表一条记录"); return null; } }
//抽象工厂接口 定义一个创建访问User表对象的抽象工厂接口+Department interface IFactory { IUser CreateUser(); IDepartment CreateDepartment(); }
//SqlServerFactory类 实现IFactory接口,实例化SqlserverUser和SqlserverDepartment class SqlServerFactory : IFactory { public IUser CreateUser() { return new AccessUser(); } public IDepartment CreateDepartment() { return new SqlserverDepartment(); } }
//AccessFactory类 实现IFactory接口,实例化AccessUser和AccessDepartment class AccessFactory : IFactory { public IUser CreateUser() { return new AccessUser(); } public IDepartment CreateDepartment() { return new AccessDepartment(); } }
//客户端 class Program { static void Main(string[] args) { User user = new User(); Department dept = new Department(); //IFactory factory = new SqlServerFactory(); IFactory factory = new AccessFactory(); IUser iu = factory.CreateUser(); iu.Insert(user); iu.GetUser(1); IDepartment id = factory.CreateDepartment(); id.Insert(dept); id.GetDepartment(1); Console.Read(); } }
组成类图
抽象工厂模式的构成(以上述为例)
AbstractProductA和AbstractProductB是两个抽象产品。
ProductA1,ProductA2,ProducB1,ProductB2就是对两个抽象产品的具体分类的实现。
IFactory是一个抽象工厂接口。它里面包含所有的产品创建的抽象方法。
ConcreteFactory1和ConcreteFactory2就是具体的工厂了。为创建不同的产品对象,客户端应使用不同的具体工厂。
抽象工厂模式的优缺点
优:1.它易于交换产品系列。由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
2.它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操作实例,产品的具体类也被具体工厂的实现分离,不会出现在客户代码中。
缺:1.不能更灵活的满足需求的变换。如果需求来自于增加功能,要改动的地方就会很多。不方便。
2.无法解决客户端有多个程序类的情况,会造成大批量的改动。
使用场景
1.系统不依赖于产品类实例如何被创建,组合和表达的细节。
2.系统的产品有多于一个的产品族,而系统只消费其中某一族的产品
3.同属于同一个产品族是在一起使用的。这一约束必须在系统的设计中体现出来。
4.系统提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于实现。