工厂三兄弟之工厂方法模式(三)

转载 2013年12月05日 20:20:58

文章转载:http://blog.csdn.net/lovelion/article/details/9307137


3 完整解决方案

        Sunny公司开发人员决定使用工厂方法模式来设计日志记录器,其基本结构如图3所示:

日志记录器结构图

       在图3中,Logger接口充当抽象产品,其子类FileLogger和DatabaseLogger充当具体产品,LoggerFactory接口充当抽象工厂,其子类FileLoggerFactory和DatabaseLoggerFactory充当具体工厂。完整代码如下所示:

[java] view plaincopy
  1. //日志记录器接口:抽象产品  
  2. interface Logger {  
  3.     public void writeLog();  
  4. }  
  5.   
  6. //数据库日志记录器:具体产品  
  7. class DatabaseLogger implements Logger {  
  8.     public void writeLog() {  
  9.         System.out.println("数据库日志记录。");  
  10.     }  
  11. }  
  12.   
  13. //文件日志记录器:具体产品  
  14. class FileLogger implements Logger {  
  15.     public void writeLog() {  
  16.         System.out.println("文件日志记录。");  
  17.     }  
  18. }  
  19.   
  20. //日志记录器工厂接口:抽象工厂  
  21. interface LoggerFactory {  
  22.     public Logger createLogger();  
  23. }  
  24.   
  25. //数据库日志记录器工厂类:具体工厂  
  26. class DatabaseLoggerFactory implements LoggerFactory {  
  27.     public Logger createLogger() {  
  28.             //连接数据库,代码省略  
  29.             //创建数据库日志记录器对象  
  30.             Logger logger = new DatabaseLogger();   
  31.             //初始化数据库日志记录器,代码省略  
  32.             return logger;  
  33.     }     
  34. }  
  35.   
  36. //文件日志记录器工厂类:具体工厂  
  37. class FileLoggerFactory implements LoggerFactory {  
  38.     public Logger createLogger() {  
  39.             //创建文件日志记录器对象  
  40.             Logger logger = new FileLogger();   
  41.             //创建文件,代码省略  
  42.             return logger;  
  43.     }     
  44. }  

       编写如下客户端测试代码:

[java] view plaincopy
  1. class Client {  
  2.     public static void main(String args[]) {  
  3.         LoggerFactory factory;  
  4.         Logger logger;  
  5.         factory = new FileLoggerFactory(); //可引入配置文件实现  
  6.         logger = factory.createLogger();  
  7.         logger.writeLog();  
  8.     }  
  9. }  

       编译并运行程序,输出结果如下:

文件日志记录。

 

4 反射与配置文件

       为了让系统具有更好的灵活性和可扩展性,Sunny公司开发人员决定对日志记录器客户端代码进行重构,使得可以在不修改任何客户端代码的基础上更换或增加新的日志记录方式。

       在客户端代码中将不再使用new关键字来创建工厂对象,而是将具体工厂类的类名存储在配置文件(如XML文件)中,通过读取配置文件获取类名字符串,再使用Java的反射机制,根据类名字符串生成对象。在整个实现过程中需要用到两个技术:Java反射机制与配置文件读取。软件系统的配置文件通常为XML文件,我们可以使用DOM (Document Object Model)SAX (Simple API for XML)StAX (Streaming API for XML)等技术来处理XML文件。关于DOMSAXStAX等技术的详细学习大家可以参考其他相关资料,在此不予扩展。

微笑

扩展

关于JavaXML的相关资料,大家可以阅读Tom MyersAlexander Nakhimovsky所著的《Java XML编程指南》一书或访问developer Works 中国中的“Java XML 技术专题”,参考链接:

http://www.ibm.com/developerworks/cn/xml/theme/x-java.html

       Java反射(Java Reflection)是指在程序运行时获取已知名称的类或已有对象的相关信息的一种机制,包括类的方法、属性、父类等信息,还包括实例的创建和实例类型的判断等。在反射中使用最多的类是ClassClass类的实例表示正在运行的Java应用程序中的类和接口,其forName(String className)方法可以返回与带有给定字符串名的类或接口相关联的 Class对象,再通过Class对象的newInstance()方法创建此对象所表示的类的一个新实例,即通过一个类名字符串得到类的实例。如创建一个字符串类型的对象,其代码如下:

[java] view plaincopy
  1. //通过类名生成实例对象并将其返回  
  2. Class c=Class.forName("String");  
  3. Object obj=c.newInstance();  
  4. return obj;  

       此外,在JDK中还提供了java.lang.reflect包,封装了其他与反射相关的类,此处只用到上述简单的反射代码,在此不予扩展。

       Sunny公司开发人员创建了如下XML格式的配置文件config.xml用于存储具体日志记录器工厂类类名:

[html] view plaincopy
  1. <!— config.xml -->  
  2. <?xml version="1.0"?>  
  3. <config>  
  4.     <className>FileLoggerFactory</className>  
  5. </config>  

       为了读取该配置文件并通过存储在其中的类名字符串反射生成对象,Sunny公司开发人员开发了一个名为XMLUtil的工具类,其详细代码如下所示:

[java] view plaincopy
  1. //工具类XMLUtil.java  
  2. import javax.xml.parsers.*;  
  3. import org.w3c.dom.*;  
  4. import org.xml.sax.SAXException;  
  5. import java.io.*;  
  6.   
  7. public class XMLUtil {  
  8. //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象  
  9.     public static Object getBean() {  
  10.         try {  
  11.             //创建DOM文档对象  
  12.             DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();  
  13.             DocumentBuilder builder = dFactory.newDocumentBuilder();  
  14.             Document doc;                             
  15.             doc = builder.parse(new File("config.xml"));   
  16.           
  17.             //获取包含类名的文本节点  
  18.             NodeList nl = doc.getElementsByTagName("className");  
  19.             Node classNode=nl.item(0).getFirstChild();  
  20.             String cName=classNode.getNodeValue();  
  21.               
  22.             //通过类名生成实例对象并将其返回  
  23.             Class c=Class.forName(cName);  
  24.             Object obj=c.newInstance();  
  25.             return obj;  
  26.         }     
  27.         catch(Exception e) {  
  28.             e.printStackTrace();  
  29.             return null;  
  30.          }  
  31.     }  
  32. }  

       有了XMLUtil类后,可以对日志记录器的客户端代码进行修改,不再直接使用new关键字来创建具体的工厂类,而是将具体工厂类的类名存储在XML文件中,再通过XMLUtil类的静态工厂方法getBean()方法进行对象的实例化,代码修改如下:

[java] view plaincopy
  1. class Client {  
  2.     public static void main(String args[]) {  
  3.         LoggerFactory factory;  
  4.         Logger logger;  
  5.         factory = (LoggerFactory)XMLUtil.getBean(); //getBean()的返回类型为Object,需要进行强制类型转换  
  6.         logger = factory.createLogger();  
  7.         logger.writeLog();  
  8.     }  
  9. }  

       引入XMLUtil类和XML配置文件后,如果要增加新的日志记录方式,只需要执行如下几个步骤:

       (1) 新的日志记录器需要继承抽象日志记录器Logger

       (2) 对应增加一个新的具体日志记录器工厂,继承抽象日志记录器工厂LoggerFactory,并实现其中的工厂方法createLogger(),设置好初始化参数和环境变量,返回具体日志记录器对象;

       (3) 修改配置文件config.xml,将新增的具体日志记录器工厂类的类名字符串替换原有工厂类类名字符串;

       (4) 编译新增的具体日志记录器类和具体日志记录器工厂类,运行客户端测试类即可使用新的日志记录方式,而原有类库代码无须做任何修改,完全符合“开闭原则”。

      通过上述重构可以使得系统更加灵活,由于很多设计模式都关注系统的可扩展性和灵活性,因此都定义了抽象层,在抽象层中声明业务方法,而将业务方法的实现放在实现层中。

疑问

思考

       有人说:可以在客户端代码中直接通过反射机制来生成产品对象,在定义产品对象时使用抽象类型,同样可以确保系统的灵活性和可扩展性,增加新的具体产品类无须修改源代码,只需要将其作为抽象产品类的子类再修改配置文件即可,根本不需要抽象工厂类和具体工厂类。

       试思考这种做法的可行性?如果可行,这种做法是否存在问题?为什么?



【作者:刘伟 http://blog.csdn.net/lovelion


工厂三兄弟之简单工厂模式(一)

工厂模式是最常用的一类创建型设计模式,通常我们所说的工厂模式是指工厂方法模式,它也是使用频率最高的工厂模式。本章将要学习的简单工厂模式是工厂方法模式的“小弟”,它不属于GoF 23种设计模式,但在软件...
  • LoveLion
  • LoveLion
  • 2013年07月11日 14:24
  • 22932

设计模式—工厂三兄弟

前言设计模式一共有23种,光工厂模式就有三种,刚开始学的时候还能分的清楚,到后面越来越像了,总的来说目的都是为了易维护,易拓展;手段是封装继承和多态;原则是上篇博客写到的六大原则。但是既然这是前人留下...
  • HEJI1103
  • HEJI1103
  • 2016年11月27日 15:12
  • 475

工厂三兄弟之工厂方法模式(一)

简单工厂模式虽然简单,但存在一个很严重的问题。当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背“开闭原则”,如何实现增加新产品而不影响...
  • LoveLion
  • LoveLion
  • 2013年07月12日 09:45
  • 17980

工厂三兄弟之工厂方法模式(三)

3 完整解决方案        Sunny公司开发人员决定使用工厂方法模式来设计日志记录器,其基本结构如图3所示:图3 日志记录器结构图       在图3中,Logger接口充当抽象产品,其子类Fi...
  • LoveLion
  • LoveLion
  • 2013年07月12日 10:35
  • 17189

工厂三兄弟之抽象工厂模式(四)

4 完整解决方案       Sunny公司开发人员使用抽象工厂模式来重构界面皮肤库的设计,其基本结构如图6所示:图6 界面皮肤库结构图       在图6中,SkinFactory接口充当抽象工厂,...
  • LoveLion
  • LoveLion
  • 2013年07月13日 16:47
  • 14038

三兄弟旗舰版TI28335DSP—核心板GPIO电灯操作—CCS6

操作GPIO点灯可以使用 1、GPIODAT  数据寄存器
  • wujunbo27
  • wujunbo27
  • 2014年08月23日 17:30
  • 2278

再次回顾设计模式——工厂三姐妹

设计模式可谓再熟悉不过了,工厂三姐妹是设计模式中最常见的,也是面试中最常问的,但是就在昨天联想面试的时候面试官问我工厂方法和抽象工厂的区别,我心里特别明白两者之间的关系,但是就是用语言组织不起来,说了...
  • u010926964
  • u010926964
  • 2015年10月27日 14:35
  • 1471

工厂三兄弟之简单工厂模式(三)

3 完整解决方案为了将Chart类的职责分离,同时将Chart对象的创建和使用分离,Sunny软件公司开发人员决定使用简单工厂模式对图表库进行重构,重构后的结构如图2所示: 在图2中,Chart接口...
  • will130
  • will130
  • 2016年01月02日 21:33
  • 155

工厂三兄弟之抽象工厂模式(三)

文章转载:http://blog.csdn.net/lovelion/article/details/9319423 3 抽象工厂模式概述        抽象工厂模式为创建一组...
  • wangeclipse
  • wangeclipse
  • 2013年12月05日 20:12
  • 370

工厂三兄弟之简单工厂模式(三)

3 完整解决方案        为了将Chart类的职责分离,同时将Chart对象的创建和使用分离,Sunny软件公司开发人员决定使用简单工厂模式对图表库进行重构,重构后的结构如图2所示: 图...
  • bigpudding24
  • bigpudding24
  • 2015年04月28日 13:39
  • 324
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:工厂三兄弟之工厂方法模式(三)
举报原因:
原因补充:

(最多只允许输入30个字)