Java工厂模式详解.doc_第1页
Java工厂模式详解.doc_第2页
Java工厂模式详解.doc_第3页
Java工厂模式详解.doc_第4页
Java工厂模式详解.doc_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

工厂模式1. 简单工厂模式(Simple Factory)从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。该模式中包含的角色及其职责: (1)工厂(Creator)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。 (2)抽象产品(Product)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。 (3)具体产品(Concrete Product)角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。使用场景:工厂类负责创建的对象比较少;客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。应用举例:对于一个典型的Java应用而言,应用之中各实例之间存在复杂的调用关系(Spring把这种调用关系成为依赖关系,例如A实例调用B实例来的方法,则成为A依赖与B)。当A对象需要调用B对象的方法是,许多初学者会选择使用new关键字来创建一个B实例,然后调用B实例的方法。从语法角度来看,这种做法没有任何问题,这种做法的坏处在于:A类的方法实现直接调用了B类的类名(这种方式也被称为硬编码耦合),一旦系统需要重构;需要使用C类来代替B类时,程序不得不写A类代码。如果应用中有100个或10000个类以硬编码耦合了B类,则需要重新改写100个,10000个地方.换一个角度来看这个问题:对于A对象而言,它只需要调用B对象的方法,并不关心B对象的实现、创建过程。考虑让B类实现一个IB接口,而A类只需要IB接口耦合A类并不直接使用new关键字来创建B实例,而是重新定义一个工厂类:IBFactory,由该工厂类来负责创建IB实例;而A类通过IBFactory工厂的方法得到IB的实例。通过该用上面设计,则A类需要与IBFactory耦合,和需要与IB接口耦合,如果系统需要重构:需要使用C类代替B类,则只需要让C类实现IB接口,并改写IBFactory工厂中创建IB实例的实现代码,并让该工厂产生C(实现IB接口)实例即可、由于所以来IB实例的对象都是通过工厂来获取IB实例的,所以他们都将改为获得C类实例,这就完成了系统重构。示例:Output接口public interface Output public final static Integer MAX_CACHE_LINE=3;void getData(String str);void out();Pinter类实现Output接口public class Printer implements Output private String printData=new StringMAX_CACHE_LINE;/用以记录当前需打印的作业数private int dataNum=0;Overridepublic void getData(String str) if(dataNum=MAX_CACHE_LINE)System.out.println(输出队列一满,添加失败);elseprintDatadataNum+=str;Overridepublic void out() while(dataNum0)System.out.println(打印机打印:+printData0);/把作业整体前移一位,并将剩下的作业数减一System.arraycopy(printData, 1, printData, 0, -dataNum);工厂类,返回实现了Output接口的Printer的实例public class OutputFactory public Output getOutput()return new Printer();Computer类对接口Output形成依赖,将Computer与Printer实现类分离开来public class Computer private Output out;public Computer(Output out)this.out=out;public void keyIn(String str)out.getData(str);public void print()out.out();public static void main(String args) OutputFactory of=new OutputFactory();Computer c=new Computer(of.getOutput();c.keyIn(轻量级);c.keyIn(Struts);c.print();如果系统需要重构,则只需要让替换类实现Output接口,并改下OutputFactory类的getOutput方法即可。优势: 工厂类是整个模式的关键,包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类让对象的调用这和对象创建过程分离,当对象调用这需要对象是,直接向工厂请求即可。而不必管这些对象究竟如何创建及如何组织的。从而避免了对象的调用者和对象的实现以硬编码方式耦合,提高系统的可维护性、可扩展性。缺点: 当产品修改时,工厂类也要做相应的修改。由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求。这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;这些缺点在工厂方法模式中得到了一定的克服。对Spring容器而言,它首先是一个巨大的工程,它负责创建所有Bean实例,整个应用的所有组件都有Spring容器负责创建。不仅如此,Spring容器扩展了这种简单工厂模式,它还可以管理Bean实例,Spring工厂将会返回同一个Bean实例之间的依赖关系;而且,如果容器中Bean实例具有singleton行为特征,则Spring容器还会缓存改Bean实例,从而保证程序通过Spring工厂来获取Bean实例时,Spring工厂将会返回同一个Bean实例。下面示例提供一份Spring配置文件的XML文件,程序提供一个扩展的工厂类,该工厂类也可提供类似SpringIoC容器的功能。首先我们改写Computer类:package simpleFactory;public class Computer private Output out;private String name;public String getName() return name;public void setName(String name) = name;public Output getOut() return out;public void setOut(Output out) this.out = out;public Computer() public Computer(Output out) this.out = out;public void keyIn(String str) out.getData(str);public void print() out.out();然后提供一个实现Output接口的类,此类与Printer基本相同,只是改变了输出:package simpleFactory;public class BetterPrinter implements Output private String printData=new StringMAX_CACHE_LINE*2;/用以记录当前需打印的作业数private int dataNum=0;Overridepublic void getData(String str) if(dataNum=MAX_CACHE_LINE)System.out.println(输出队列一满,添加失败);elseprintDatadataNum+=str;Overridepublic void out() while(dataNum0)System.out.println(打印机打印1:+printData0);/把作业整体前移一位,并将剩下的作业数减一System.arraycopy(printData, 1, printData, 0, -dataNum);接着新建一个接口:package ioc;public interface ApplicationContext Object getBean(String name) throws Exception;提供一个配置文件:最后提供实现ApplicationContext接口的类:package ioc;import java.io.File;import java.lang.reflect.Method;import java.util.Collections;import java.util.HashMap;import java.util.Map;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;public class SJxmlApplicationContext implements ApplicationContext /保存容器中所有单利模式的Bean对象private Map objPool = Collections.synchronizedMap(new HashMap();/保存对应文件中的Document对象private Document doc;/保存配置文件中的根元素private Element root;public SJxmlApplicationContext(String filePath) throws ExceptionSAXReader reader=new SAXReader();doc=reader.read(new File(filePath);root=doc.getRootElement();initPool();initProp();public Object getBean(String name) throws ExceptionObject target=objPool.get(name);/对于singleton Bean,容器已经初始化了所有Bean实例if(target.getClass()!=String.class)return target;elseString clazz=(String) target;/对于prototype并未注入属性值return Class.forName(clazz).newInstance();/初始化容器中的所有singleton Beanprivate void initPool() throws Exception/遍历配置文件里每个元素for(Object obj:root.elements()Element beanEle=(Element) obj;/取得元素的id属性String beanId=beanEle.attributeValue(id);/取得元素的class属性String beanClazz=beanEle.attributeValue(class);/取得元素的scope属性String beanScope=beanEle.attributeValue(scope);/如果scope属性不存在,或为singletonif(beanScope=null|beanScope.equals(singleton)/从默认的构造器创建Bean实例,并将其放入objPool中objPool.put(beanId, Class.forName(beanClazz).newInstance();else/对于非singleton Bean,存放该Bean实现类的类名objPool.put(beanId, beanClazz);private void initProp() throws Exceptionfor(Object obj:root.elements()Element beanEle=(Element)obj;/取得元素的id属性String beanId=beanEle.attributeValue(id);/取得元素的scope属性String beanScope=beanEle.attributeValue(scope);if(beanScope=null|beanScope.equals(singleton)/取出objPool指定的bean实例Object bean=objPool.get(beanId);/遍历元素的每个元素for(Object prop:beanEle.elements()Element propEle=(Element) prop;/取得name属性的值String propName=propEle.attributeValue(name);/取得value属性的值String propValue=propEle.attributeValue(value);/取得元素的ref属性String propRef=propEle.attributeValue(ref);/将属性的首字母大写String propNameCamelize=propName.substring(0,1).toUpperCase()+propName.substring(1, propName.length();/如果元素的value属性值存在if(propValue!=null&propValue.length()0)Method setter=bean.getClass().getMethod(set+propNameCamelize, String.class);/执行setter注入setter.invoke(bean, propValue);if(propRef!=null&propRef.length()0)/取得需要被依赖注入的Bean实例Object target=objPool.get(propRef);/objPool池中不存在指定Bean实例if(target=null)/此处还应处理singleton Bean依赖prototype Bean的情形/定义设置注入所需的setter方法Method setter=null;/遍历target对象所实现的所有接口for(Class superInterface:target.getClass().getInterfaces()setter=bean.getClass().getMethod(set+propNameCamelize, superInterface);/如果成功取得该接口对应的方法,直接跳出循环break;/如果setter方法依然是null/则直接取得target实现对应的setter方法if(setter=null)setter=bean.getClass().getMethod(set+propNameCamelize, target.getClass();/执行setter注入setter.invoke(bean, target);测试代码为:package ioc;import simpleFactory.Computer;import simpleFactory.Printer;public class IocTest public static void main(String args) throws Exception /Computer c=(Computer) Class.forName(simpleFactory.Computer).newInstance();ApplicationContext ctx=new SJxmlApplicationContext(bean.xml);Computer c=(Computer) ctx.getBean(computer);/c.setOut(new Printer();c.keyIn(疯狂);c.keyIn(struts);c.print();System.out.println(c.getName();System.out.println(ctx.getBean(now);2. 工厂方法模式(Factory Method) 在简单工厂模式里,系统使用ProductFactory工厂类生产所有产品的实例,且该工厂决定生产哪个类的实例,即该工厂负责所有的逻辑判断,实例创建等工作。如果我们不想在工厂类中进行逻辑判断,程序可以为不同产品类提供不同的工厂,不同的工厂类生产不同的产品。例如我们为上面的Printer、BetterPrinter分别提供PrinterFactory和BetterPrinterFactory工厂类,这就无需在工厂类进行复杂的逻辑判断。示例:将OutputFactory改为一个接口,并为该接口提供两个实现类:PrinterFactory.java和BetterPrinterFactory.java。package simpleFactory;public interface OutputFactory Output getOutput();package simpleFactory;public class PrinterFactory implements OutputFactory Overridepublic Output getOutput() / TODO Auto-generated method stubreturn new Printer();package simpleFactory;public class BetterPrinterFactory implements OutputFactory Overridepublic Output getOutput() / TODO Auto-generated method stubreturn new BetterPrinter();工厂方法中各类之间的类图:ComputerOutputPrinterPrinterfactoryOutputFactoryBetterPrinterBetterPrinterFactory当使用工厂方法设计模式时,对象调用者需要与具体的工厂类耦合:当需要不同对象时,程序需要调用相应工厂对象的方法来得到所需的对象。public static void main(String args) /使用Printerfactory子类来创建OutputFactory;OutputFactory of=new PrinterFactory();/将Output对象传入,创建Computer对象;Computer c=new Computer(of.getOutput();c.keyIn(struts);c.keyIn(指南);c.print();当客户端代码需要调用Output对象的方法时,为了得到不同的Output实例,程序必须显式创建不同的OutputFactory实例。从上面的代码可以看出,对于采用工厂方法设计的架构,客户端代码成功是与被调用对象的实现类分类,但带来了另一种耦合:客户端代码与不同的工厂类耦合。为了解决客户端代码与不同工厂类耦合的问题,接着考虑再增加一个工厂类,该工厂类不是生产Output对性,而是生产outputFactory实例简而言之,这个工厂不制造具体的被调用对性,而是制造不同工厂对象。这个特殊的工厂实例被称呼为抽象工厂类,这种设计方式也被称为抽象工厂模式。3. 抽象工厂模式(Abstract Factory) ComputerOutputPrinterPrinterfactoryOutputFactoryBetterPrinterBetterPrinterFactoryOutputFactoryFactorygetOutputFactory(String type) OutputFactory从上图可以看出,在这种模式下系统新增了一个OutputFactoryFactory工厂类,该工厂提供了一个getOutputFactory(String type)方法,改方法用于返回一个OutputFactory工厂实例。package simpleFactory;public class OutputFactoryFactory public static OutputFactory getOutputFactory(String type)/将此 String 与另一个 String 比较,不考虑大小写。/如果两个字符串的长度相同,并且其中的相应字符都相等(忽略大小写),/则认为这两个字符串是相等的if(type.equalsIgnoreCase(better)return new BetterPrinterFactory();elsereturn new PrinterFactory();从上面代码可以看出,抽象工厂根据type参数进行判断,决定需要生产那种工厂实例。通过这种设计模式,就可让客户端程序只需与抽象工厂类耦合。public static void main(String args) /使用Printerfactory子类来创建OutputFactory;OutputFactory of=OutputFactoryFactory.getOutputFactory(better);/将Output对象传入,创建Computer对象;Computer c=new Computer(of.getOutput();c.keyIn(struts);c.keyIn(指南);c.print();上面的程序中产生一个OutputFactory工厂,但具体产生那个工厂则由outputFactoryFactory抽象工厂决定,不同的工厂对象产生不同的Output对象。通过采用抽象工厂的设计模式,系统可以让客户端代码与被调用对象的是迅雷、具体的工厂类分离。更进一步,我们可以将控制产生工厂的字符提取出来,由配置文件制定。即OutputFactory of=OutputFactoryFactory.getOutputFactory(better);中的“better”抽取出来,从配置文件中指定。public static void main(String args) Properties p=new Properties();try File file=new File(src/perties);p.load(new FileInputStream(file); catch (IOException e) / TODO Auto-generated catch blocke.printStackTrace();/使用Printerfactory子类来创建OutputFactory;OutputFactory of=OutputFactoryFactory.getOutputFactory(p.getProperty(factorybean);/将Output对象传入,创建Computer对象;Computer c=new Computer(of.getOutput();c.keyIn(struts);c.keyIn(指南);c.print();pertiesfactorybean=better详解Spring中bean的scope singleton prototype request. 2010-12-03 14:54这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。在spring2.0之前bean只有2种作用域即:singleton(单例)、non-singleton(也称prototype), Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。! 1、singleton作用域当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。配置实例:或者 2、prototypeprototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)3、requestrequest表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例: request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置:如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可: org.springframework.web.context.request.RequestContextListener4、sessionsession作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效5、global sessionglobal session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用6、自定义bean装配作用域在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和prototype),spring的作用域由接口org.springframework.beans.factory.con*.Scope来定义,自定义自己的作用域只要实现该接口即可再议singleton与prototype:scope=prototype没写的问题,项目中对一个表的增删该操作是用一个action,这个 actionadd,update,delete,save这些方法, 添加和修改是共用一个页面,当页面得到id时代表进行的修改操作,反之是添加操作。因为在配置spring的bean是忘了写 scope=prototype 所以每次添加时都显示最后一次访问过的记录,scope=prototype 会在该类型的对象被请求 时创建一个新的action对象。如果没有配置scope=prototype则添加的时候不会新建一个action,他任然会保留上次访问的过记录的信息 webwork的Acti

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论