写在前面
最近看spring的源代码。发现之前没有完全弄懂(工厂方法、抽象工厂)的区别。
spring中代理对象的产生,是通过代理工厂(工厂模式),首先spring中的代理是使用jdk或者cglib的代理,只要看目标类是否实现接口。
public class ProxyFactory extends ProxyCreatorSupport { //createAopProxy()方法是通过AopProxyFactory获取AopProxy(JDK,CGLIB) public Object getProxy() { return createAopProxy().getProxy(); } }
这里典型应用了工厂模式
工厂接口:
public interface AopProxyFactory { AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException; }
目标产品:
AopProxy
----CglibAopProxy------ObjenesisCglibAopProxy
----JdkDynamicAopProxy
工厂实现类:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } }
(这其实是一个简单的抽象工程模式),待会再来分析。我们先进入主题
1 简单工程模式
产品接口(抽象产品)
public interface AOPProxy { }
产品实现类(具体产品)
public class JDKAOPProxy implements AOPProxy{ }
public class CGLIBAOPProxy implements AOPProxy{ }
工厂类(简单工程)
public class AopProxyFactory { AOPProxy createJDKAOPProxy(){ return new JDKAOPProxy(); } AOPProxy createCGLIBAOPProxy(){ return new CGLIBAOPProxy(); } }
说明:这便是简单工厂模式了,首先,符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品。下面我们从开闭原则上来分析下简单工厂模式。当未来增加了一个AopProxy的时候(MYAOPProxy),只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。(即创建一个新的子类(MYAOPProxy),继承抽象产品AOPProxy)那么 对于产品部分来说,它是符合开闭原则的——对扩展开放、对修改关闭;但是工厂类不太理想,因为每增加AopProxy,都要在工厂类中增加相应的商业逻辑和判 断逻辑,这显自然是违背开闭原则的。
而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝类坏了。
正如我前面提到的简单工厂模式适用于业务简单的情况下或者具体产品很少增加的情况。而对于复杂的业务环境可能不太适应了。这就应该由工厂方法模式来出场了!!
2 工程方法模式
抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
来用类图来清晰的表示下的它们之间的关系:
抽象产品
public interface AOPProxy { }
具体产品
public class JDKAOPProxy implements AOPProxy{ }
public class CGLIBAOPProxy implements AOPProxy{ }
抽象工厂接口
public interface AopProxyFactory { AOPProxy createAOPProxy(); }
工厂实现
public class CGLIBAopProxyFactory implements AopProxyFactory{ @Override public AOPProxy createAOPProxy() { return new CGLIBAOPProxy(); } }
public class JDKAopProxyFactory implements AopProxyFactory{ @Override public AOPProxy createAOPProxy() { return new JDKAOPProxy(); } }
说明:使用开闭原则来分析下工厂方法模式。当有新的产品(MYAOPProxy)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。(即当有新产品时,只要创建并基础抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类)工厂方法模式是完全符合开闭原则的!
使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。
当然特殊的情况,就要特殊对待了:对于系统中存在不同的产品树,而且产品树上存在产品族(下一节将解释这个名词)。那么这种情况下就可能可以使用抽象工厂模式了。
3 抽象工厂模式
加入现在有一个新的产品叫做OOPProxy也有两种实现JDKOOPProxy、CGLIBOOPProxy,这样工厂方法模式实现(工厂方法模式只有单一的产品组)。
抽象产品AOPProxy
public interface AOPProxy { }
抽象产品AOPProxy实现
public class JDKAOPProxy implements AOPProxy{ }
public class CGLIBAOPProxy implements AOPProxy{ }
抽象产品OOPProxy
public interface OOPProxy { }
抽象产品OOPProxy实现
public class JDKOOPProxy implements OOPProxy{ }
public class CGLIBOOPProxy implements OOPProxy{ }
抽象工厂ProxyFacoty
public interface ProxyFactory { AOPProxy createAOPProxy(); OOPProxy createOOPProxy(); }
抽象工厂实现JDKProxyFactory
public class JDKProxyFactory implements ProxyFactory{ @Override public AOPProxy createAOPProxy() { return new JDKAOPProxy(); } @Override public OOPProxy createOOPProxy() { return new JDKOOPProxy(); } }
抽象工厂实现OOPAOPFacoty
public class CGLIBProxyFactory implements ProxyFactory{ @Override public AOPProxy createAOPProxy() { return new CGLIBAOPProxy(); } @Override public OOPProxy createOOPProxy() { return new CGLIBOOPProxy(); } }
其中:JDKAOPProxy和CGLIBAOPProxy属于产品树、同理JDKOOPProxy和CGLIBOOPProxy。而JDKAOPProxy和JDKOOPProxy属于产品族。
所以抽象工厂模式一般用于具有产品树和产品族的场景下。
抽象工厂模式的缺点:如果需要增加新的产品树,那么就要新增三个产品类,比如TOPProxy,JDKTOPProxy, CGLIBTOPProxy,修改三个工厂类。这样大批量的改动是很丑陋的做法。