工厂模式:静态工厂

一般认为简单工厂模式,产品部分能够在OCP原则下应对变化(这也恰恰是使用静态工厂的意义所在),但是当新增一种产品时候,我们的工厂的static createProduct还是必须被迫修改代码,也就是不具有应对变化的能力。

     本文提供了一种先注册后使用的办法,能够对静态工厂应对变化方面有一定的改善。可能不一定具有太大的使用价值,但对于拓展思路有点启示。

     阅读前,先推荐阅读 http://www.iteye.com/topic/180972   主题:工厂模式----易懂版(转)

 

Java代码   收藏代码
  1. package com.eyesmore.staticfactory.spi;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.ByteArrayOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.ObjectInputStream;  
  7. import java.io.ObjectOutputStream;  
  8. import java.util.Collections;  
  9. import java.util.HashMap;  
  10. import java.util.Map;  
  11.   
  12. import com.eyesmore.staticfactory.BenzCar;  
  13.   
  14. public class CarRegisteryFactory {  
  15.   
  16.     private static Map<String,Car> registery = Collections.synchronizedMap(new HashMap<String,Car>());  
  17.       
  18.     public static boolean registerCar(String name,Car car) {  
  19.         if(registery.containsKey(name)) <strong><span style="color: #ff0000;">{//注意:可能导致非线程安全</span>  
  20.   
  21. </strong>  
  22.   
  23.   
  24.             return false;  
  25.         }  
  26.         registery.put(name, car);  
  27.         return true;  
  28.     }  
  29.       
  30.     public static boolean unregisterCar(String name) {  
  31.         if(!registery.containsKey(name)) {  
  32.             return false;  
  33.         }  
  34.         registery.remove(name);  
  35.         return true;  
  36.     }  
  37.       
  38.     public static boolean containsCar(String name) {  
  39.         return registery.containsKey(name);  
  40.     }  
  41.       
  42.     public static Car createCar(String name) throws NoSuchCarException {  
  43.         if(!registery.containsKey(name)) {  
  44.             throw new NoSuchCarException("CarName = "+name);  
  45.         }  
  46.         <strong><span style="background-color: #00ff00;">/* create a new instance according to the registered one*/  
  47.         Car template = registery.get(name);  
  48.         return cloneInstance(template);</span>  
  49.   
  50. </strong>  
  51.   
  52.   
  53.     }  
  54.   
  55.     /* Extract Method from createCar */  
  56.     private static Car cloneInstance(Car template) {  
  57.         Car cloneInstance = null;  
  58.         /* 
  59.          * clone an instance by ObjectOutputStream/ObjectInputStream 
  60.          * */  
  61.         try {  
  62.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  63.             ObjectOutputStream oos = new ObjectOutputStream(baos);  
  64.             oos.writeObject(template);  
  65.             ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));  
  66.             cloneInstance = (Car)ois.readObject();  
  67.               
  68.         } catch (IOException e) {//一般只会在调试时发生  
  69.             e.printStackTrace();  
  70.         } catch (ClassNotFoundException e) {  
  71.             e.printStackTrace();  
  72.         }  
  73.         return cloneInstance;  
  74.     }  
  75.       
  76.       
  77.       
  78.     public static void main(String[] args) {  
  79.   
  80.         Car templateInstance = new BenzCar();  
  81.         CarRegisteryFactory.registerCar("Benz", templateInstance);  
  82.         Car car1 = CarRegisteryFactory.createCar("Benz");  
  83.         car1.drive();  
  84.         Car car2 = CarRegisteryFactory.createCar("Benz");  
  85.         car2.drive();  
  86.         <strong>System.out.println("(templateInstance == car1):"+(templateInstance == car1));  
  87.         System.out.println("(templateInstance == car2):"+(templateInstance == car2));  
  88.         System.out.println("(car1 == car2):"+(car1 == car2));//创建的是不同的对象</strong>  
  89.   
  90.   
  91.     }  
  92.   
  93. }  

 

 

其他代码:

Java代码   收藏代码
  1. package com.eyesmore.staticfactory.spi;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public interface Car extends Serializable {//重要对象一般推荐继承Serializable   
  6.   
  7.     public void drive();  
  8. }  

 

Java代码   收藏代码
  1. package com.eyesmore.staticfactory;  
  2.   
  3. import com.eyesmore.staticfactory.spi.Car;  
  4.   
  5. public class BenzCar implements Car {  
  6.   
  7.     private static final long serialVersionUID = -6849794470754667222L;  
  8.       
  9.     public void drive() {  
  10.         System.out.println("Benz ...");  
  11.     }  
  12.   
  13. }  

 

 

如果此时要增加Audi,我们的CarRegisterFactory足以应对它。

 

Java代码   收藏代码
  1. package com.eyesmore.staticfactory;  
  2.   
  3. import com.eyesmore.staticfactory.spi.Car;  
  4.   
  5. public class AudiCar implements Car {  
  6.   
  7.     private static final long serialVersionUID = -6849794470754667111L;  
  8.       
  9.     public void drive() {  
  10.         System.out.println("Audi ...");  
  11.     }  
  12.   
  13. }  

 

使用时候,先在CarRegisterFactory.registerCar("Audi",new AudiCar());

然后要用的时候则CarRegisterFactory.createCar("Audi");

 

当然也可以通过配置文件+发射的方式对注册器进行初始化。另外,静态工厂的那个方法的实现有很多种不同的策略,比如log4j的Logger.getLogger,被创建的对象会被重复使用。

 

==============================================================

【补充】  以上我们通过createInstance()都是重新克隆出一个新的对象实例。当然,很多时候我们并不重新生成新的对象。单例模式我们经常用到Factory.getInstance(); 但是这样导致一个程序只能有一个实例,我们常常需要Factory去维护一个对象名称到对象实例的一个映射关系,典型的就是Log4j,Logger.getLogger(name)。

==============================================================

Factory维护一个name代码   收藏代码
  1. // store instances of pools  
  2.     private static Map<String,SockIOPool> pools =  
  3.         new HashMap<String,SockIOPool>();  
  4.   
  5.   
  6.   
  7.     // empty constructor  
  8.     protected SockIOPool() { }  
  9.   
  10.   
  11. /**   
  12.      * Factory to create/retrieve new pools given a unique poolName.   
  13.      *   
  14.      * @param poolName unique name of the pool  
  15.      * @return instance of SockIOPool  
  16.      */  
  17.     public static synchronized SockIOPool getInstance( String poolName ) {  
  18.         if ( pools.containsKey( poolName ) )  
  19.             return pools.get( poolName );  
  20.   
  21.         SockIOPool pool = new SockIOPool();  
  22.         pools.put( poolName, pool );  
  23.   
  24.         return pool;  
  25.     }  
  26.   
  27.     /**   
  28.      * Single argument version of factory used for back compat.  
  29.      * Simply creates a pool named "default".   
  30.      *   
  31.      * @return instance of SockIOPool  
  32.      */  
  33.     public static SockIOPool getInstance() {  
  34.         return getInstance( "default" );  
  35.     }  
 

 

使用静态工厂模式,目的可能不一定是考虑把对象的创建局部在Factory内部,以后修改时只需要修改工厂的代码。从Log4j的例子可以看出使用静态工厂模式还有个好处是方便对象实例的存取,因为如果一个重要对象在很多地方都需要使用,那么作为参数传递还是很不方便的,这常常迫使我们在面向对象时怀念以前过程化程序语言中的全程过程,也就是java的静态方法。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值