一、前情回顾
1、简单工厂 VS 工厂方法VS抽象工厂:
[简单工厂 VS 工厂方法VS抽象工厂](http://blog.csdn.net/wangyy130/article/details/24867685)
2、设计模式总结 :
[设计模式总结](http://blog.csdn.net/wangyy130/article/details/25273161)
其实在之前刚接触设计模式的时候,对于三工厂模式理解的并不是特别到位,尤其是为什么在一些时候我们会用简单工厂来代替抽象工厂,
始终不是特别的理解。毕竟简单工厂并没有列入GOF的23个设计模式之中
啊。那么今天,就关于DRP这个项目中的架构演化来分析一下简单工厂取代抽象工厂的前因后果吧!
二、DRP架构之抽象工厂
在DRP中初衷为了解决便于适应多种数据库格式编码,采用了抽象工厂架构模式。那么具体如何使用的,且看一张图。
说明:此图并未将所有的系列都画出来。只是为了说明冗余类的庞大。这里只是画出了Dao层,其实我们还需要在逻辑层B建立抽象工厂,
以便于让servlet来方便创建对应的业务逻辑层的实例。
从图中我们可以看出,为了使用抽象工厂来适应多数据库的情况,
仅物料一个类别就必须多加三个类,那如果一个项目中的业务类达到上百个之多的话,那得增加多少个类啊,还有如果我们还想再逻辑层再解耦的话,
如果再使用抽象工厂,这样的话,出现的冗余也太多了,是不是就应该考虑其他的模式了呢?
三、DRP架构之简单工厂
那么为了减少冗余,我们用简单工厂来代替了抽象工厂,看一下类图:
看上面这张类图,看着似乎类也并没有少了多少啊,再仔细看看,其实这张类图早已包含了业务逻辑B层和数据访问D层两层的实现类和工厂的关系了。
在这个图中我们发现为创建类而多出来的只有BeanFacoty这一个工厂类。在这个工厂类中,为了进一步解耦,我们使用了读取配置文件的方法,
来随时变更适合我们的实现类,这样就不用害怕数据库更换了。这样相比抽象工厂就简单多了吧。
四、DRP简单工厂代码实现
光说不练假把式,我们来看一下具体的代码吧!
配置文件:bean-sys.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<service-class>
<service id="com.bjpowernode.drp.basedata.manager.ItemManager" class="com.bjpowernode.drp.basedata.manager.ItemManagerImpl"/>
</service-class>
<dao-class>
<dao id="com.bjpowernode.drp.basedata.dao.ItemDao" class="com.bjpowernode.drp.basedata.dao.ItemDao4OracleImpl" />
</dao-class>
</beans>
beanFactory对配置文件的读取:
public class BeanFactory {
private final String beansConfigFile="beans-config.xml";
private Document doc;
private static BeanFactory instance=new BeanFactory();
private Map serviceMap=new HashMap();
private Map daoMap=new HashMap();
private BeanFactory(){
try {
doc=new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
} catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
public static BeanFactory getInstance(){
return instance;
}
/**
* 根据产品编号取得service系列产品,对应业务逻辑层
* @param beanId
* @return
*/
public synchronized Object getServiceObject(Class c){
if(serviceMap.containsKey(c.getName())){
return serviceMap.get(c.getName());
}
Element beanElt=(Element) doc.selectSingleNode("//service[@id=\""+c.getName()+"\"]");
String className=beanElt.attributeValue("class");
Object service=null;
try {
service=Class.forName(className).newInstance();
serviceMap.put(c.getName(), service);
} catch (Exception e) {
throw new RuntimeException("创建失败");
}
return service;
}
/**
* 根据产品编号取得dao系列产品
* @param beanId
* @return
*/
public synchronized Object getDaoObject(Class c){
if(daoMap.containsKey(c.getName())){
return daoMap.get(c.getName());
}
Element beanElt=(Element) doc.selectSingleNode("//dao[@id=\""+c.getName()+"\"]");
String className=beanElt.attributeValue("class");
Object dao=null;
try {
dao=Class.forName(className).newInstance();
daoMap.put(c.getName(), dao);
} catch (Exception e) {
throw new RuntimeException("创建失败");
}
return dao;
}
}
当然,这里为了防止在调用时容易造成的书写错误,采用了类的全名来作为id值,这样我们读取的时候就可以直接按类名读取,
如果一旦拼写出错,编译是不能通过的。所以大大方便了程序的编写。
程序的调用:
itemManager=(ItemManager)beanFactory.getInstance().getServiceObject(ItemManager.class)
怎么样,是不是简单了许多呢?虽然简单工厂并没有满足OCP原则,但是通过上面的比较,我们发现,如果采用简单工厂,在简单工厂中只需要两个方法就
可以实现B和D两层类的实例创建,而采用抽象工厂却要徒劳的多增加很多类,这样比较下来,还是采用简单工厂更加适合。
这里把设计模式没有最好只有更好的特点体现的淋漓尽致了吧!