意图
提供一个创建一系列相关活相互依赖对象的接口,而无需指定他们具体的类。(G4)
任务
假设我们需要进行各种数据库操作,可是我们有很多的选择啊,JDBC,Hibernate,Ibatis等等。本来选择一个就OK了,可是变态的Boss为了炫耀我们的技术如何如何强大,竟说我们能够无成本地在这三个解决方案间切换。这下系统该怎么设计呢?
或许你已经注意到 每种解决方案自身都是完备而独立的,不错,这便是解决问题的切入点。提供一套解决方案公有行为的接口,各个解决方案分别实现这些接口,同时建立一个创建各个解决方案的工厂(Factory)。这不就完成任务了吗?哈哈。
首先我们从使用者的角度出发,总结出一套数据库操作的方法,在这里我们称为 Service。假设我们只需要一个行为,就是work(),内容是打印出这是来自哪个解决方案。
java 代码
- /**
- * 业务类接口
- */
- public interface Service {
- /**
- * 运行业务
- */
- void work();
- }
然后我们根据这个接口分别实现各个解决方案的相应实现。
java 代码
- /**
- * A体系中的业务实现
- */
- public class ServiceA implements Service {
-
- public void work() {
- System.out.println("这是A体系中业务。");
- }
- }
java 代码
- /**
- * B体系中的业务实现
- */
- public class ServiceB implements Service {
- public void work() {
- System.out.println("这是B体系中业务。");
- }
- }
大概各位都碰到过需求不断变更,Service不断增加的情况吧。只有一个Service可不够用啊,保不准等会儿Boss就调研回来,需要新增加一个Service2,Service3......ServiceN。如果都写到Service接口里,那可是变成巨无霸了。汉堡包巨无霸我喜欢,代码巨无霸我可就不喜欢了。于是给这些Service建立一个 工厂(Factory),以方便地创建各种Service。
那么我们首先来建立一个Factory的接口类。
java 代码
- /**
- * 工厂接口
- */
- public interface Factory {
- /**
- * 建立创建Service的抽象接口,由各实现的工厂来创建具体的Service
- */
- Service createService();
- }
下面就来实现各个解决方案的工厂。
java 代码
- /**
- * 具体的实现工厂A
- */
- public class FactoryA implements Factory {
- public Service createService() {
- // 创建本体系中的Service实现
- return new ServiceA();
- }
- }
java 代码
- /**
- * 具体的实现工厂B
- */
- public class FactoryB implements Factory {
-
- public Service createService() {
- // 创建本体系中的Service实现
- return new ServiceB();
- }
- }
或许各位看官会说这不就是工厂模式嘛,怎么又在前面加上“抽象”二字,难不成是故弄玄虚?非也非也。前头说过了,我们解决问题的切入点是“每种解决方案自身都是完备而独立的”,所以这些具体的各种解决方案的工厂对Consumer也应该是透明的。于是我们给这些工厂(解决方案)加上一个工厂,也就是我们通过这个工厂来生成一整套的解决方案。这个工厂便是我们要说的 AbstractFactory。
java 代码
- /**
- * 抽象工厂
- */
- public class AbstractFactory {
- /**
- * 根据不同的体系要求创建出不同的业务工厂
- *
- * @param factoryName
- * @return
- */
- public static AbstractFactory getFactory(String factoryName) {
- AbstractFactory ist = null;
- if (factoryName.equalsIgnoreCase("A")) {
- ist = new FactoryA();
- } else if (factoryName.equalsIgnoreCase("B")) {
- ist = new FactoryB();
- }
- return ist;
- }
- }
本着重构的精神,也为了给点事 AbstractFactory做,我便把它和接口Factory合而为一,成为一个抽象类。大概这便是这种设计模式名字的由来吧。呵呵。
java 代码
- /**
- * 抽象工厂
- */
- public abstract class AbstractFactory {
- /**
- * 根据不同的体系要求创建出不同的业务工厂
- *
- * @param factoryName
- * @return
- */
- public static AbstractFactory getFactory(String factoryName) {
- AbstractFactory ist = null;
- if (factoryName.equalsIgnoreCase("A")) {
- ist = new FactoryA();
- } else if (factoryName.equalsIgnoreCase("B")) {
- ist = new FactoryB();
- }
- return ist;
- }
- /**
- * 建立创建Service的抽象接口,由各实现的工厂来创建具体的Service
- */
- public abstract Service createService();
- }
相应的,FactoryA和FactoryB修改为
java 代码
- public class FactoryA extends AbstractFactory {
- ......
- }
- public class FactoryB extends AbstractFactory {
- ......
- }
这样,各种解决方案间的切换便十分容易了。
java 代码
- /**
- * 业务的消费者
- *
- * @author 聪明的笨蛋
- * @email [email protected]
- */
- public class Consumer {
- public void work() {
- Service service = null;
- // 实现A体系中的业务
- service = AbstractFactory.getFactory("A").createService();
- service.work();
- // 实现B体系中的业务
- service = AbstractFactory.getFactory("B").createService();
- service.work();
- }
- //运行
- public static void main(String[] args) {
- Consumer csm = new Consumer();
- csm.work();
- }
- }
恩,Mission completed!剩下的就是各个解决方案的实现了,哈哈。那些工作就让,就让.......没有人做,还是我做吧.....谁叫俺是小弟呢。唉~
小结
正如我上面举的这个例子,抽象工厂模式主要适用于需要提供若干种不同实现体系,但又要求有相同处理要求的时候。如Portal技术中,各种Portlet便是不同的体系,但我们在处理Portal的时候都是把他们统一当作Portlet实现,同样这种解决问题的思路可以用在SOA中。这种设计模式大多出现在各个系统进行集成的时候。
题外话
对于上面的抽象工厂中,AbstractFactory依赖于其各子类Factory,这是不合适的。因为这样一来,我们的工程中如果只使用其中一种Factory时,却不得不背上其他用不上的Factory。在这里多做一些改进工作,使用类似于spring中管理bean的方式,对各Factory进行管理。
首先我们需要规定好一种管理格式,在这里以xml为例吧。
xml 代码
- <beans>
- <bean id="A" class="com.javaeye.smartfool.FactoryA" />
- <bean id="B" class="com.javaeye.smartfool.FactoryB" />
- </beans>
这样,我们可以在AbstractFactory加入一个读配置的方法getXmlClass,通过输入id值来读出其对应的class名。这样,我们的AbstractFactory变成
java 代码
- public abstract class AbstractFactory {
- // 读取配置文件
- private static String getXmlClass(String id){
- ......
- }
- public static AbstractFactory getFactory(String factoryName) {
- AbstractFactory ist = null;
- String className = getXmlClass(factoryName);
- try {
- ist = (AbstractFactory) Class.forName(className).newInstance();
- } catch (Exception e) {
- e.printStackTrace();
- ist = null;
- }
- return ist;
- }
- public abstract Service createService();
- }
这样,就可以解除AbstractFactory对子类的依赖了。
更多的关于此类依赖的设计实践可以参考without ejb这书,上面有很多非常好的思想,绝对能受益非浅。