抽象工厂模式,相对于前2种工厂模式,引入了“产品族”的概念。
何为产品族?以之前的运算器为例,之前讨论的都是局限于“运算器”这个产品,而现在,我要为其加上前缀:“工厂1生产的运算器”,“工厂2生产的运算器”。
这就是产品族,对象拥有相同的行为,但却是有不同的实现。
那么现在来看,运算器这个例子,可能已经不能特别直观地,将抽象工厂模式展示出来,我们换一个场景。
模拟场景:
我需要去创建用户(User)和部门(Department)两个对象,但是底层需要用的数据库(DB2 和 MySQL),可能产生变化,所以需要两套解决方案。
思想:
首先,针对需要创建的对象,需要一个抽象工厂(AbsFactory),负责创建抽象用户(AbsUser)和抽象部门(AbsDepartment)。
根据底层的数据库,抽象工厂拥有两个实现,DB2 工厂(FactoryDB2)和 MySQL 工厂(FactoryMySQL)。
每个工厂各司其职,创建对应的继承抽象类的对象。
UML:
分析:
以上是一个针对给出情景的完整 UML 类图。
为用户(User)定义了两种行为,而部门(Department)没有定义方法。
在用户的 joinDepartment() 方法中,缺少一条依赖(Dependency)的虚线。由于多态的性质对于入参无能为力,所以类似的情形,需要在方法内部进行向下转型。
可以看出,抽象方法模式(Abstract Factory),其实就是将多个工厂方法模式(Factory Method)组装在一起。
代码:
1 public abstract class AbsFactory { 2 3 protected abstract AbsUser createUser(); 4 5 protected abstract AbsDepartment createDepartment(); 6 7 }
1 public abstract class AbsUser { 2 3 protected void joinDepartment(AbsDepartment department) { 4 System.out.println(this.toString() + "不能加入任何部门"); 5 } 6 7 protected abstract void personalMethod(); 8 9 @Override 10 public String toString() { 11 return this.getClass().getSimpleName().substring(4) + "用户"; 12 } 13 14 }
1 public abstract class AbsDepartment { 2 3 @Override 4 public String toString() { 5 return this.getClass().getSimpleName().substring(10) + "部门"; 6 } 7 8 }
1 public final class FactoryDB2 extends AbsFactory { 2 3 @Override 4 public UserDB2 createUser() { 5 return new UserDB2(); 6 } 7 8 @Override 9 public DepartmentDB2 createDepartment() { 10 return new DepartmentDB2(); 11 } 12 13 }
1 public final class FactoryMySQL extends AbsFactory { 2 3 @Override 4 public UserMySQL createUser() { 5 return new UserMySQL(); 6 } 7 8 @Override 9 public DepartmentMySQL createDepartment() { 10 return new DepartmentMySQL(); 11 } 12 13 }
1 public final class UserDB2 extends AbsUser { 2 3 @Override 4 public void personalMethod() { 5 System.out.println("DB2用户的个人行为"); 6 } 7 8 }
1 public final class UserMySQL extends AbsUser { 2 3 @Override 4 public void personalMethod() { 5 System.out.println("MySQL用户的个人行为"); 6 } 7 8 @Override 9 public void joinDepartment(AbsDepartment department) { 10 if (department instanceof DepartmentMySQL) { 11 department = (DepartmentMySQL) department; 12 } else { 13 throw new RuntimeException("只接受 MySQL数据库创建的部门"); 14 } 15 System.out.println(this.toString() + "加入部门:" + department.toString()); 16 } 17 18 }
1 public final class DepartmentDB2 extends AbsDepartment { 2 3 }
1 public final class DepartmentMySQL extends AbsDepartment { 2 3 }
Junit 即测试客户端调用:
1 public final class AbsFactoryTest { 2 3 @Test 4 public void test1() { 5 AbsUser user = new UserDB2(); 6 AbsDepartment department = new DepartmentDB2(); 7 user.joinDepartment(department); 8 user.personalMethod(); 9 } 10 11 @Test 12 public void test2() { 13 AbsUser user = new UserMySQL(); 14 AbsDepartment department = new DepartmentMySQL(); 15 user.joinDepartment(department); 16 user.personalMethod(); 17 } 18 19 }
JUnit 控制台输出:
总结:
从客户端的调用情况,可以发现,只要修改顶层工厂(每个产品的抽象父类,对应在工厂方法模式中,就是一个工厂)的方式,就可以改变创建的具体对象,体现了良好的封装性。
产品具体的约束,由产品内部实现,客户端无需关心。
使用抽象工厂模式,在设计之初,必须考虑到 AbsFactory 中生产的所有对象。如果后期需要在工厂中多生产一个角色(Role),不但修改困难,而且从顶层开始就破坏了封装性,违反了开闭原则。
如果需要增加一种对象实现的方式,比如 Oracle 实现,虽然要增加的对象同样很多,但是既不会打破代码的封装性,也不会与现有的代码产生耦合,是可以接受的情况。
抽象工厂模式,去除那些业务场景之外,在数据库连接(ORM 框架)和操作系统相关(Java 的平台无关性),有着很好的实践。
原文:http://www.cnblogs.com/jing-an-feng-shao/p/7544309.html