工厂模式:静态工厂

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

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

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

Java代码 收藏代码
  1. packagecom.eyesmore.staticfactory.spi;
  2. importjava.io.ByteArrayInputStream;
  3. importjava.io.ByteArrayOutputStream;
  4. importjava.io.IOException;
  5. importjava.io.ObjectInputStream;
  6. importjava.io.ObjectOutputStream;
  7. importjava.util.Collections;
  8. importjava.util.HashMap;
  9. importjava.util.Map;
  10. importcom.eyesmore.staticfactory.BenzCar;
  11. publicclassCarRegisteryFactory{
  12. privatestaticMap<String,Car>registery=Collections.synchronizedMap(newHashMap<String,Car>());
  13. publicstaticbooleanregisterCar(Stringname,Carcar){
  14. if(registery.containsKey(name))<strong><spanstyle="color:#ff0000;">{//注意:可能导致非线程安全</span>
  15. </strong>
  16. returnfalse;
  17. }
  18. registery.put(name,car);
  19. returntrue;
  20. }
  21. publicstaticbooleanunregisterCar(Stringname){
  22. if(!registery.containsKey(name)){
  23. returnfalse;
  24. }
  25. registery.remove(name);
  26. returntrue;
  27. }
  28. publicstaticbooleancontainsCar(Stringname){
  29. returnregistery.containsKey(name);
  30. }
  31. publicstaticCarcreateCar(Stringname)throwsNoSuchCarException{
  32. if(!registery.containsKey(name)){
  33. thrownewNoSuchCarException("CarName="+name);
  34. }
  35. <strong><spanstyle="background-color:#00ff00;">/*createanewinstanceaccordingtotheregisteredone*/
  36. Cartemplate=registery.get(name);
  37. returncloneInstance(template);</span>
  38. </strong>
  39. }
  40. /*ExtractMethodfromcreateCar*/
  41. privatestaticCarcloneInstance(Cartemplate){
  42. CarcloneInstance=null;
  43. /*
  44. *cloneaninstancebyObjectOutputStream/ObjectInputStream
  45. **/
  46. try{
  47. ByteArrayOutputStreambaos=newByteArrayOutputStream();
  48. ObjectOutputStreamoos=newObjectOutputStream(baos);
  49. oos.writeObject(template);
  50. ObjectInputStreamois=newObjectInputStream(newByteArrayInputStream(baos.toByteArray()));
  51. cloneInstance=(Car)ois.readObject();
  52. }catch(IOExceptione){//一般只会在调试时发生
  53. e.printStackTrace();
  54. }catch(ClassNotFoundExceptione){
  55. e.printStackTrace();
  56. }
  57. returncloneInstance;
  58. }
  59. publicstaticvoidmain(String[]args){
  60. CartemplateInstance=newBenzCar();
  61. CarRegisteryFactory.registerCar("Benz",templateInstance);
  62. Carcar1=CarRegisteryFactory.createCar("Benz");
  63. car1.drive();
  64. Carcar2=CarRegisteryFactory.createCar("Benz");
  65. car2.drive();
  66. <strong>System.out.println("(templateInstance==car1):"+(templateInstance==car1));
  67. System.out.println("(templateInstance==car2):"+(templateInstance==car2));
  68. System.out.println("(car1==car2):"+(car1==car2));//创建的是不同的对象</strong>
  69. }
  70. }

其他代码:

Java代码 收藏代码
  1. packagecom.eyesmore.staticfactory.spi;
  2. importjava.io.Serializable;
  3. publicinterfaceCarextendsSerializable{//重要对象一般推荐继承Serializable
  4. publicvoiddrive();
  5. }

Java代码 收藏代码
  1. packagecom.eyesmore.staticfactory;
  2. importcom.eyesmore.staticfactory.spi.Car;
  3. publicclassBenzCarimplementsCar{
  4. privatestaticfinallongserialVersionUID=-6849794470754667222L;
  5. publicvoiddrive(){
  6. System.out.println("Benz...");
  7. }
  8. }

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

Java代码 收藏代码
  1. packagecom.eyesmore.staticfactory;
  2. importcom.eyesmore.staticfactory.spi.Car;
  3. publicclassAudiCarimplementsCar{
  4. privatestaticfinallongserialVersionUID=-6849794470754667111L;
  5. publicvoiddrive(){
  6. System.out.println("Audi...");
  7. }
  8. }

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

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

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

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

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

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

Factory维护一个name代码 收藏代码
  1. //storeinstancesofpools
  2. privatestaticMap<String,SockIOPool>pools=
  3. newHashMap<String,SockIOPool>();
  4. //emptyconstructor
  5. protectedSockIOPool(){}
  6. /**
  7. *Factorytocreate/retrievenewpoolsgivenauniquepoolName.
  8. *
  9. *@parampoolNameuniquenameofthepool
  10. *@returninstanceofSockIOPool
  11. */
  12. publicstaticsynchronizedSockIOPoolgetInstance(StringpoolName){
  13. if(pools.containsKey(poolName))
  14. returnpools.get(poolName);
  15. SockIOPoolpool=newSockIOPool();
  16. pools.put(poolName,pool);
  17. returnpool;
  18. }
  19. /**
  20. *Singleargumentversionoffactoryusedforbackcompat.
  21. *Simplycreatesapoolnamed"default".
  22. *
  23. *@returninstanceofSockIOPool
  24. */
  25. publicstaticSockIOPoolgetInstance(){
  26. returngetInstance("default");
  27. }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值