一般认为简单工厂模式,产品部分能够在OCP原则下应对变化(这也恰恰是使用静态工厂的意义所在),但是当新增一种产品时候,我们的工厂的static createProduct还是必须被迫修改代码,也就是不具有应对变化的能力。
本文提供了一种先注册后使用的办法,能够对静态工厂应对变化方面有一定的改善。可能不一定具有太大的使用价值,但对于拓展思路有点启示。
阅读前,先推荐阅读 http://www.iteye.com/topic/180972 主题:工厂模式----易懂版(转)
- package com.eyesmore.staticfactory.spi;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Map;
- import com.eyesmore.staticfactory.BenzCar;
- public class CarRegisteryFactory {
- private static Map<String,Car> registery = Collections.synchronizedMap(new HashMap<String,Car>());
- public static boolean registerCar(String name,Car car) {
- if(registery.containsKey(name)) <strong><span style="color: #ff0000;">{//注意:可能导致非线程安全</span>
- </strong>
- return false;
- }
- registery.put(name, car);
- return true;
- }
- public static boolean unregisterCar(String name) {
- if(!registery.containsKey(name)) {
- return false;
- }
- registery.remove(name);
- return true;
- }
- public static boolean containsCar(String name) {
- return registery.containsKey(name);
- }
- public static Car createCar(String name) throws NoSuchCarException {
- if(!registery.containsKey(name)) {
- throw new NoSuchCarException("CarName = "+name);
- }
- <strong><span style="background-color: #00ff00;">/* create a new instance according to the registered one*/
- Car template = registery.get(name);
- return cloneInstance(template);</span>
- </strong>
- }
- /* Extract Method from createCar */
- private static Car cloneInstance(Car template) {
- Car cloneInstance = null;
- /*
- * clone an instance by ObjectOutputStream/ObjectInputStream
- * */
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(template);
- ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
- cloneInstance = (Car)ois.readObject();
- } catch (IOException e) {//一般只会在调试时发生
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return cloneInstance;
- }
- public static void main(String[] args) {
- Car templateInstance = new BenzCar();
- CarRegisteryFactory.registerCar("Benz", templateInstance);
- Car car1 = CarRegisteryFactory.createCar("Benz");
- car1.drive();
- Car car2 = 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>
- }
- }
其他代码:
- package com.eyesmore.staticfactory.spi;
- import java.io.Serializable;
- public interface Car extends Serializable {//重要对象一般推荐继承Serializable
- public void drive();
- }
- package com.eyesmore.staticfactory;
- import com.eyesmore.staticfactory.spi.Car;
- public class BenzCar implements Car {
- private static final long serialVersionUID = -6849794470754667222L;
- public void drive() {
- System.out.println("Benz ...");
- }
- }
如果此时要增加Audi,我们的CarRegisterFactory足以应对它。
- package com.eyesmore.staticfactory;
- import com.eyesmore.staticfactory.spi.Car;
- public class AudiCar implements Car {
- private static final long serialVersionUID = -6849794470754667111L;
- public void drive() {
- System.out.println("Audi ...");
- }
- }
使用时候,先在CarRegisterFactory.registerCar("Audi",new AudiCar());
然后要用的时候则CarRegisterFactory.createCar("Audi");
当然也可以通过配置文件+发射的方式对注册器进行初始化。另外,静态工厂的那个方法的实现有很多种不同的策略,比如log4j的Logger.getLogger,被创建的对象会被重复使用。
==============================================================
【补充】 以上我们通过createInstance()都是重新克隆出一个新的对象实例。当然,很多时候我们并不重新生成新的对象。单例模式我们经常用到Factory.getInstance(); 但是这样导致一个程序只能有一个实例,我们常常需要Factory去维护一个对象名称到对象实例的一个映射关系,典型的就是Log4j,Logger.getLogger(name)。
==============================================================
- // store instances of pools
- private static Map<String,SockIOPool> pools =
- new HashMap<String,SockIOPool>();
- // empty constructor
- protected SockIOPool() { }
- /**
- * Factory to create/retrieve new pools given a unique poolName.
- *
- * @param poolName unique name of the pool
- * @return instance of SockIOPool
- */
- public static synchronized SockIOPool getInstance( String poolName ) {
- if ( pools.containsKey( poolName ) )
- return pools.get( poolName );
- SockIOPool pool = new SockIOPool();
- pools.put( poolName, pool );
- return pool;
- }
- /**
- * Single argument version of factory used for back compat.
- * Simply creates a pool named "default".
- *
- * @return instance of SockIOPool
- */
- public static SockIOPool getInstance() {
- return getInstance( "default" );
- }
使用静态工厂模式,目的可能不一定是考虑把对象的创建局部在Factory内部,以后修改时只需要修改工厂的代码。从Log4j的例子可以看出使用静态工厂模式还有个好处是方便对象实例的存取,因为如果一个重要对象在很多地方都需要使用,那么作为参数传递还是很不方便的,这常常迫使我们在面向对象时怀念以前过程化程序语言中的全程过程,也就是java的静态方法。