抽象工厂模式(abstract factory)
定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
UML图
例子
在开发的过程难免会遇到更换数据库的事情,也就意味着会出现大量的代码修改。而使用抽象工厂模式,可以很好的避免修改的行为。现在有两个操作对象,一个是用户,一个是部门,都具有插入和查询的功能。
POJO
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: User.java * @Description: 用户类 * @author: Han * @date: 2016年6月24日 下午8:31:32 */ public class User { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: Department.java * @Description: 部门表 * @author: Han * @date: 2016年6月24日 下午8:32:15 */ public class Department { private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } }
针对User表操作的接口
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: IUser.java * @Description: 接口设计:针对User表操作接口 * @author: Han * @date: 2016年6月24日 下午8:56:38 */ public interface IUser { //插入一条用户 public void insert(User user); //得到一个用户 public User getUser(String id); }
Oracle对User表的操作
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: OracleUser.java * @Description: Oracle对User表的操作 * @author: Han * @date: 2016年6月24日 下午8:58:27 */ public class OracleUser implements IUser { @Override public void insert(User user) { System.out.println("Oracle 添加了一个用户"); } @Override public User getUser(String id) { System.out.println("Oracle 查询了一个用户"); return null; } }
SqlServer对User表的操作
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: SqlserverUser.java * @Description: SqlServer对User表的操作 * @author: Han * @date: 2016年6月24日 下午8:59:08 */ public class SqlserverUser implements IUser { @Override public void insert(User user) { System.out.println("SqlServer 添加了一个用户"); } @Override public User getUser(String id) { System.out.println("SqlServer 查询了一个用户"); return null; } }
针对Department表操作的接口
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: IDepartment.java * @Description: 接口设计:针对部门表的操作 * @author: Han * @date: 2016年6月24日 下午8:59:58 */ public interface IDepartment { public void insert(Department department); public Department getDecpartment(int id); }
Oracle对Department表的操作
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: OracleDepartment.java * @Description: Oracle对部门表的具体操作 * @author: Han * @date: 2016年6月24日 下午9:00:44 */ public class OracleDepartment implements IDepartment { @Override public void insert(Department department) { System.out.println("Oracle 插入了一个部门"); } @Override public Department getDecpartment(int id) { System.out.println("Oracle 得到了一个部门"); return null; } }
SqlServer对部门表的操作
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: SqlserverDepartment.java * @Description: SqlServer对部门表的操作 * @author: Han * @date: 2016年6月24日 下午9:01:29 */ public class SqlserverDepartment implements IDepartment { @Override public void insert(Department department) { System.out.println("SqlServer 添加了一个部门"); } @Override public Department getDecpartment(int id) { System.out.println("SqlServer 查询了一个部门"); return null; } }
重点,对于数据库选择的接口设计
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: IFactory.java * @Description: 接口设计:对数据库选择 * @author: Han * @date: 2016年6月24日 下午9:03:00 */ public interface IFactory { public IUser createUser(); public IDepartment createDepartment(); }
Oracle工厂
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: OracleFactory.java * @Description: Oracle工厂 * @author: Han * @date: 2016年6月24日 下午9:03:33 */ public class OracleFactory implements IFactory { @Override public IUser createUser() { return new OracleUser(); } @Override public IDepartment createDepartment() { return new OracleDepartment(); } }
SqlServer工厂
package com.csdhsm.pattemdesign.abstractfactory; /** * @Title: SqlserverFactory.java * @Description: SqlServer工厂 * @author: Han * @date: 2016年6月24日 下午9:04:06 */ public class SqlserverFactory implements IFactory { @Override public IUser createUser() { return new SqlserverUser(); } @Override public IDepartment createDepartment() { return new SqlserverDepartment(); } }
客户端
package com.csdhsm.pattemdesign.abstractfactory; public class Solution { public static void main(String[] args) { User user = new User(); Department department = new Department(); IFactory factory = new OracleFactory(); //如果要改成Sqlserver数据库,只需要该这里就可以了 //IFactory factory = new SqlserverFactory(); IUser iu = factory.createUser(); iu.insert(user); iu.getUser("1"); IDepartment id = factory.createDepartment(); id.insert(department); id.getDecpartment(1); } }
结果
OK,成功!
与工厂模式比较
抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广。
如果使用工厂模式,上面的例子会以OracleUser,OracleDepartment,SqlServerUser,SqlServerDepartment来生成工厂,而使用了抽象工厂模式,是按照Oracle,SqlServer来进行生成工厂,这样会更清晰,无论是对于Oracle数据库,还是SqlServer数据库,执行的方法都差不多,所以使用抽象工厂模式会很好。
假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品。这里的产品等级就是指Oracle和SqlServer。
总结
优点
- 分离接口和实现
客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。
- 使切换产品族变得容易
因为一个具体的工厂实现代表的是一个产品族,比如上面例子的从Oracle数据库到SqlServer数据库只需要切换一下具体工厂。
缺点
- 不太容易扩展新的产品
如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。
参考资料:http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html