一般认为简单工厂模式,产品部分能够在OCP原则下应对变化(这也恰恰是使用静态工厂的意义所在),但是当新增一种产品时候,我们的工厂的static createProduct还是必须被迫修改代码,也就是不具有应对变化的能力。
本文提供了一种先注册后使用的办法,能够对静态工厂应对变化方面有一定的改善。可能不一定具有太大的使用价值,但对于拓展思路有点启示。
阅读前,先推荐阅读http://www.iteye.com/topic/180972主题:工厂模式----易懂版(转)
- packagecom.eyesmore.staticfactory.spi;
- importjava.io.ByteArrayInputStream;
- importjava.io.ByteArrayOutputStream;
- importjava.io.IOException;
- importjava.io.ObjectInputStream;
- importjava.io.ObjectOutputStream;
- importjava.util.Collections;
- importjava.util.HashMap;
- importjava.util.Map;
- importcom.eyesmore.staticfactory.BenzCar;
- publicclassCarRegisteryFactory{
- privatestaticMap<String,Car>registery=Collections.synchronizedMap(newHashMap<String,Car>());
- publicstaticbooleanregisterCar(Stringname,Carcar){
- if(registery.containsKey(name))<strong><spanstyle="color:#ff0000;">{//注意:可能导致非线程安全</span>
- </strong>
- returnfalse;
- }
- registery.put(name,car);
- returntrue;
- }
- publicstaticbooleanunregisterCar(Stringname){
- if(!registery.containsKey(name)){
- returnfalse;
- }
- registery.remove(name);
- returntrue;
- }
- publicstaticbooleancontainsCar(Stringname){
- returnregistery.containsKey(name);
- }
- publicstaticCarcreateCar(Stringname)throwsNoSuchCarException{
- if(!registery.containsKey(name)){
- thrownewNoSuchCarException("CarName="+name);
- }
- <strong><spanstyle="background-color:#00ff00;">/*createanewinstanceaccordingtotheregisteredone*/
- Cartemplate=registery.get(name);
- returncloneInstance(template);</span>
- </strong>
- }
- /*ExtractMethodfromcreateCar*/
- privatestaticCarcloneInstance(Cartemplate){
- CarcloneInstance=null;
- /*
- *cloneaninstancebyObjectOutputStream/ObjectInputStream
- **/
- try{
- ByteArrayOutputStreambaos=newByteArrayOutputStream();
- ObjectOutputStreamoos=newObjectOutputStream(baos);
- oos.writeObject(template);
- ObjectInputStreamois=newObjectInputStream(newByteArrayInputStream(baos.toByteArray()));
- cloneInstance=(Car)ois.readObject();
- }catch(IOExceptione){//一般只会在调试时发生
- e.printStackTrace();
- }catch(ClassNotFoundExceptione){
- e.printStackTrace();
- }
- returncloneInstance;
- }
- publicstaticvoidmain(String[]args){
- CartemplateInstance=newBenzCar();
- CarRegisteryFactory.registerCar("Benz",templateInstance);
- Carcar1=CarRegisteryFactory.createCar("Benz");
- car1.drive();
- Carcar2=CarRegisteryFactory.createCar("Benz");
- car2.drive();
- <strong>System.out.println("(templateInstance==car1):"+(templateInstance==car1));
- System.out.println("(templateInstance==car2):"+(templateInstance==car2));
- System.out.println("(car1==car2):"+(car1==car2));//创建的是不同的对象</strong>
- }
- }
其他代码:
- packagecom.eyesmore.staticfactory.spi;
- importjava.io.Serializable;
- publicinterfaceCarextendsSerializable{//重要对象一般推荐继承Serializable
- publicvoiddrive();
- }
- packagecom.eyesmore.staticfactory;
- importcom.eyesmore.staticfactory.spi.Car;
- publicclassBenzCarimplementsCar{
- privatestaticfinallongserialVersionUID=-6849794470754667222L;
- publicvoiddrive(){
- System.out.println("Benz...");
- }
- }
如果此时要增加Audi,我们的CarRegisterFactory足以应对它。
- packagecom.eyesmore.staticfactory;
- importcom.eyesmore.staticfactory.spi.Car;
- publicclassAudiCarimplementsCar{
- privatestaticfinallongserialVersionUID=-6849794470754667111L;
- publicvoiddrive(){
- System.out.println("Audi...");
- }
- }
使用时候,先在CarRegisterFactory.registerCar("Audi",new AudiCar());
然后要用的时候则CarRegisterFactory.createCar("Audi");
当然也可以通过配置文件+发射的方式对注册器进行初始化。另外,静态工厂的那个方法的实现有很多种不同的策略,比如log4j的Logger.getLogger,被创建的对象会被重复使用。
==============================================================
【补充】 以上我们通过createInstance()都是重新克隆出一个新的对象实例。当然,很多时候我们并不重新生成新的对象。单例模式我们经常用到Factory.getInstance(); 但是这样导致一个程序只能有一个实例,我们常常需要Factory去维护一个对象名称到对象实例的一个映射关系,典型的就是Log4j,Logger.getLogger(name)。
==============================================================
- //storeinstancesofpools
- privatestaticMap<String,SockIOPool>pools=
- newHashMap<String,SockIOPool>();
- //emptyconstructor
- protectedSockIOPool(){}
- /**
- *Factorytocreate/retrievenewpoolsgivenauniquepoolName.
- *
- *@parampoolNameuniquenameofthepool
- *@returninstanceofSockIOPool
- */
- publicstaticsynchronizedSockIOPoolgetInstance(StringpoolName){
- if(pools.containsKey(poolName))
- returnpools.get(poolName);
- SockIOPoolpool=newSockIOPool();
- pools.put(poolName,pool);
- returnpool;
- }
- /**
- *Singleargumentversionoffactoryusedforbackcompat.
- *Simplycreatesapoolnamed"default".
- *
- *@returninstanceofSockIOPool
- */
- publicstaticSockIOPoolgetInstance(){
- returngetInstance("default");
- }
使用静态工厂模式,目的可能不一定是考虑把对象的创建局部在Factory内部,以后修改时只需要修改工厂的代码。从Log4j的例子可以看出使用静态工厂模式还有个好处是方便对象实例的存取,因为如果一个重要对象在很多地方都需要使用,那么作为参数传递还是很不方便的,这常常迫使我们在面向对象时怀念以前过程化程序语言中的全程过程,也就是java的静态方法。