现在的位置: 首页 > 综合 > 正文

设计模式:简单工厂、工厂方法、抽象工厂之小结与区别

2013年10月10日 ⁄ 综合 ⁄ 共 14043字 ⁄ 字号 评论关闭

简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性。

本文是本人对这三种模式学习后的一个小结以及对他们之间的区别的理解。

简单工厂

简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。

不修改代码的话,是无法扩展的。

 

工厂方法

工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。

在同一等级结构中,支持增加任意产品。

 

抽象工厂

抽象工厂是应对产品族概念的。比如说,每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。

应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。

 

小结

★工厂模式中,重要的是工厂类,而不是产品类。产品类可以是多种形式,多层继承或者是单个类都是可以的。但要明确的,工厂模式的接口只会返回一种类型的实例,这是在设计产品类的时候需要注意的,最好是有父类或者共同实现的接口。

★使用工厂模式,返回的实例一定是工厂创建的,而不是从其他对象中获取的。

★工厂模式返回的实例可以不是新创建的,返回由工厂创建好的实例也是可以的。

区别

简单工厂 : 用来生产同一等级结构中的任意产品。(对于增加新的产品,无能为力)

工厂模式 :用来生产同一等级结构中的固定产品。(支持增加任意产品)  
抽象工厂:用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)  

以上三种工厂 方法在等级结构和产品族这两个方向上的支持程度不同。所以要根据情况考虑应该使用哪种方法。  

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/superbeck/archive/2009/08/14/4446177.aspx

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

 

简单工厂、工厂方法、抽象工厂

简单工厂(Simple Factory Pattern)

简单工厂模式,把对象(统一接口)的创建封装起来,而不去用了解对象所代表的真正的实现类及其初始化过程。我们只需要把参数传递给简单工厂,工厂就会根据你的需要返回相应的产品对象。示例代码如下:

Java代码 复制代码 收藏代码
  1. Iproduct.java   
  2. public interface IProduct    
  3. {   
  4.     void work();   
  5. }   
  6.     
  7. Product1.java   
  8. public class Product1 implements IProduct    
  9. {   
  10.     @Override  
  11.     public void work()    
  12.     {   
  13.         System.out.println(this.getClass().getSimpleName());   
  14.     }   
  15. }   
  16.     
  17. Product2.java   
  18. public class Product2 implements IProduct    
  19. {   
  20.     @Override  
  21.     public void work()    
  22.     {   
  23.         System.out.println(this.getClass().getSimpleName());   
  24.     }   
  25. }   
  26.     
  27. SimpleFactory.java   
  28. public class SimpleFactory    
  29. {   
  30.     public IProduct newProduct(String strcase)    
  31.     {   
  32.         IProduct pro = null;   
  33.         if(strcase.equals("product1"))   
  34.         {   
  35.             pro = new Product1();   
  36.         }   
  37.         else  
  38.         {   
  39.             if(strcase.equals("product2"))   
  40.             {   
  41.                 pro = new Product2();   
  42.             }   
  43.         }   
  44.         return pro;   
  45.     }   
  46. }   
  47.     
  48. SimpleFactoryApp.java   
  49. public class SimpleFactoryApp    
  50. {   
  51.     public static void main(String[] args)    
  52.     {   
  53.         IFactory factory = new SimpleFactory();   
  54.            
  55.         IProduct pro1 = factory.newProduct("product1");   
  56.         IProduct pro2 = factory.newProduct("product2");   
  57.            
  58.         pro1.work();   
  59.         pro2.work();   
  60.     }   
  61. }  

Product1和Product1都实现了Iproduct接口;在SimpleFactory的newProduct()方法中,根据传入的参数不同,我们实例化实现Iproduct接口的不同Product,并返回给调用方;而在SimpleFactoryApp中,我们不必知道factory是返回了哪一种Product,也不必知道他的创建过程,只知道它是一个Product,直接用就可以了。

这样做的好处就是把耦合放进了factory,调用方和product不再耦合,放在factory的原因也是因为调用方是多变的,而factory是固定的(相对而言),也就是说比如对Product1和Product2而言,车间A会用到,车间B也会用到,如果不用Factory的话,车间A和车间B的代码就会和Product1和Product2耦合,如果现在要求根据调用方上下文改变,如果车间A只能用Product1,车间B只能用Product2,那么我们要同时修改车间A和车间B的代码,或者有更多的车间需要处理呢;如果有Factory的话呢,我只要在Factory中根据上下文来判断返回相应的Product就可以了。

方法工厂(Method Factory Pattern)

简单工厂模式把所有的重心放到工厂类上,一旦向系统增加新的产品,就必须修改工厂类,不满足开闭原则(对修改关闭,对扩展开放);工厂方法模式提供一个抽象的工厂接口,在不同的产品结构上实现不同的产品工厂具体类来创建该层次中的产品,通常一个具体工厂创建一个具体产品。在新增产品的时候,只需要实现新的对应工厂就可以满足需要,是符合开闭原则的。
示例代码如下:

Java代码 复制代码 收藏代码
  1. Iproduct.java, Product1.java,Product2.java和上面的一样。   
  2.     
  3. ImethodFactory.java   
  4. public interface IMethodFactory   
  5. {   
  6.     IProduct newProduct();   
  7. }   
  8.     
  9. MethodFactorySub1.java   
  10. public class MethodFactorySub1 implements IMethodFactory    
  11. {   
  12.     @Override  
  13.     public IProduct newProduct()    
  14.     {   
  15.         return new Product1();   
  16.     }   
  17. }   
  18.     
  19. MethodFactorySub2.java   
  20. public class MethodFactorySub2 implements IMethodFactory   
  21. {   
  22.     @Override  
  23.     public IProduct newProduct()    
  24.     {   
  25.         return new Product2();   
  26.     }   
  27. }   
  28.     
  29. MethodFactoryApp.java   
  30. public class MethodFactoryApp    
  31. {   
  32.     /**  
  33.      * @param args  
  34.      */  
  35.     public static void main(String[] args)    
  36.     {   
  37.         IMethodFactory methodFactory1 = new MethodFactorySub1();   
  38.         IMethodFactory methodFactory2 = new MethodFactorySub2();   
  39.            
  40.         IProduct pro1 = methodFactory1.newProduct();   
  41.         IProduct pro2 = methodFactory2.newProduct();   
  42.            
  43.         pro1.work();   
  44.         pro2.work();   
  45.     }   
  46. }  

对不同的产品的实例化,由不同的工厂来实现,每一种工厂都是生产特定的产品。

但是我有个疑问就是,虽然每个需要产品的调用方都不再和具体的产品耦合,但每一个都会和一个特定的工厂进行耦合。理解:每个调用方都仍不会受到产品耦合的关系,有工厂这一层次,让这种易变性仍然保持在工厂的层次。并且在新增Product和调用方的时候不会再影响到原先的工厂(简单工厂的话就要修改简单工厂类了),只需要增加新的工厂类并在新的调用方中调用新的工厂就可以了。

抽象工厂(abstract factory)
一个工厂有时不光生产一种产品,比如一个青铜器的兵工厂,可能不光生产青铜刀,还生产青铜剑,属于一个系列的产品。现在生产工艺升级,现在生产性能更好的铁刀,铁剑,原先的模具,融炉都不再适用,而且为了满足过渡需要,原先的工厂肯定也要保留,而且两个工厂有很多相似之处可以提取出来。两个工厂生产的产品也有很多相似之处,但一个工厂生产的不同产品的相同之处只在于他们用的生产工艺和处理过程是一样的,但产品本身是不同的。但在不同的工厂中,产品却有类似的,如青铜刀-铁刀,青铜剑-铁剑。

具体的工厂生产的是一个产品系列内的产品,不同工厂生产的是不同代的产品。

抽象工厂的UML类图大致类似上面,两个具体工厂都继承自统一的抽象工厂,抽象工厂生产一个系统的产品(即IProduct1 和IProduct2),两个具体工厂就生成具体系列的产品。

Java代码 复制代码 收藏代码
  1. IAbstractFactory.java   
  2. public interface IAbstractFactory    
  3. {   
  4.     IProduct1 getProduct1Instance();   
  5.     IProduct2 getProduct2Instance();   
  6. }   
  7.     
  8. ConcreteFactory1.java ConcreteFactory2和此类似   
  9. public class ConcreteFactory1 implements IAbstractFactory {   
  10.     
  11.     @Override  
  12.     public IProduct1 getProduct1Instance()    
  13.     {   
  14.         // TODO Auto-generated method stub   
  15.         return new Product11();   
  16.     }   
  17.     
  18.     @Override  
  19.     public IProduct2 getProduct2Instance()    
  20.     {   
  21.         // TODO Auto-generated method stub   
  22.         return new Product21();   
  23.     }    
  24. }   
  25.     
  26. IProduct1.java IProduct2和此类似   
  27. public interface IProduct1    
  28. {   
  29.     void dowork1();   
  30. }   
  31.     
  32. Product11.java Product12、Product21、Product22和此类似   
  33. public class Product11 implements IProduct1 {   
  34.     
  35.     @Override  
  36.     public void dowork1()    
  37.     {   
  38.         System.out.println(this.getClass().getSimpleName());   
  39.     }   
  40.     
  41. }   
  42.     
  43. AbstractFactoryApp.java   
  44. public class AbstractFactoryApp {   
  45.     
  46.     /**  
  47.      * @param args  
  48.      */  
  49.     public static void main(String[] args)    
  50.     {   
  51.         IAbstractFactory factory1 = new ConcreteFactory1();   
  52.         factory1.getProduct1Instance().dowork1();   
  53.         factory1.getProduct2Instance().dowork2();   
  54.            
  55.         IAbstractFactory factory2 = new ConcreteFactory2();   
  56.         factory2.getProduct1Instance().dowork1();   
  57.         factory2.getProduct2Instance().dowork2();   
  58.     }   
  59.     
  60. }  

总结
简单工厂,方法工厂和抽象工厂没有优劣之分,只有不同的应用场景而已:
  如果产品的种类是不变的,只是想隐藏产品的实例化过程和具体的产品,就可以用简单工厂,也就是没有啥是变化的。
  如果产品种类是不定的,是变化的,如果很多的话,若用简单工厂的话,简单工厂的维护就会变大,而且会对已有类产生影响(原先的代码都会因为简单工厂类的修改而重新测试)。而且传入简单工厂的参数与产品没有明确的对应,维护起来不好。在这种场景下就可以用方法工厂,对新增产品只要增加新的工厂,在新的调用方调用相应工厂就OK了,可以完全解决上面的问题。
  抽象工厂处理的场景是,产品是分代的,且每个工厂都不止生产一种类型的产品(如青铜器兵工厂生产青铜刀和青铜剑,铁兵工厂生厂铁刀和铁剑),如果工厂都生产一种类型(具体点就是功用啥几乎都不一样,在类中表现为不同接口)的产品,就退化为方法工厂了。个人感觉,方法工厂就是抽象工厂的一个特例。

工厂模式也用了不少,特别是MS的petshop中对数据库的访问,通过工厂模式可以达到自由切换SQL 和 Oracle 数据库。近来也在看设计模式的书,发现工厂模式还是有不少的扩展。结合书中的知识和我自己理解,从代码的角度来比较工厂模式各变种。

1:简单工厂模式:其作用是实例化对象而不需要客户了解这个对象属于那个具体的子类。

Java代码 复制代码 收藏代码
  1. using System;   
  2. using System.Collections;   
  3.   
  4. public class MyClass   
  5. {   
  6.     public static void Main()   
  7.     {   
  8.         //通过参数来实例化子类。   
  9.         IVehicle vehicle = FactoryVehicle.CreateVehicle("car");   
  10.         vehicle.go();   
  11.         Console.ReadLine();       
  12.     }   
  13.        
  14. }   
  15.   
  16. public class FactoryVehicle   
  17. {   
  18.     public static IVehicle CreateVehicle(string VehicleName)   
  19.     {   
  20.         switch(VehicleName.ToLower())   
  21.         {   
  22.             case "car":   
  23.             return new Car();   
  24.             case "boat":   
  25.             return new Boat();   
  26.             default:   
  27.             return new Car();   
  28.                
  29.         }   
  30.     }   
  31.   
  32. }   
  33. public interface IVehicle   
  34. {   
  35.     void go();   
  36. }   
  37. public class Car:IVehicle   
  38. {   
  39.     public void go()   
  40.     {   
  41.         Console.WriteLine("car");   
  42.     }   
  43. }   
  44. public class Boat:IVehicle   
  45. {   
  46.     public void go()   
  47.     {   
  48.         Console.WriteLine("boat");   
  49.     }   
  50. }  

2:抽象工厂:即将工厂方法也抽象出来,由具体的子类来实例化工厂。产品创建部分和简单工厂模式相同。

Java代码 复制代码 收藏代码
  1. using System;   
  2. using System.Collections;   
  3.   
  4. public class MyClass   
  5. {   
  6.     public static void Main()   
  7.     {   
  8.         //通过定义的工厂来实例化。弊端是当产品很多时需要增加很多的工厂。代码重复。   
  9.         FactoryVehicle factory = new FactoryCar();   
  10.         IVehicle vehicle = factory.CreateVehicle();   
  11.         vehicle.go();   
  12.         Console.ReadLine();       
  13.     }   
  14.        
  15. }   
  16.   
  17.   
  18. public interface FactoryVehicle   
  19. {   
  20.      IVehicle CreateVehicle();   
  21.   
  22. }   
  23.   
  24. public class FactoryCar:FactoryVehicle   
  25. {   
  26.     public IVehicle CreateVehicle()   
  27.     {   
  28.         return new Car();   
  29.     }   
  30. }   
  31.   
  32. public class FactoryBoat:FactoryVehicle   
  33. {   
  34.     public IVehicle CreateVehicle()   
  35.     {   
  36.         return new Boat();   
  37.     }   
  38. }   
  39.   
  40. public interface IVehicle   
  41. {   
  42.     void go();   
  43. }   
  44.   
  45. public class Car:IVehicle   
  46. {   
  47.     public void go()   
  48.     {   
  49.         Console.WriteLine("car");   
  50.     }   
  51. }   
  52.   
  53. public class Boat:IVehicle   
  54. {   
  55.     public void go()   
  56.     {   
  57.         Console.WriteLine("boat");   
  58.     }   
  59. }  

3:反射工厂模式: 其实就是通过反射的方式来获得具体实例化是那个类。

Java代码 复制代码 收藏代码
  1. using System;   
  2. using System.Collections;   
  3. using System.Reflection;   
  4.   
  5. public class MyClass   
  6. {   
  7.     public static void Main()   
  8.     {   
  9.         //使用反射的方法获得实例化的类   
  10.         IVehicle vechicle = ReflectFactory.CreateVehicleByReflect("Car");   
  11.         vechicle.go();   
  12.         Console.ReadLine();       
  13.            
  14.     }   
  15.        
  16. }   
  17.   
  18. public class ReflectFactory   
  19. {   
  20.     public static IVehicle CreateVehicleByReflect(string typeName)   
  21.     {   
  22.         Type type = Type.GetType(typeName);   
  23.         ConstructorInfo  ci = type.GetConstructor(System.Type.EmptyTypes);;   
  24.         return (IVehicle)ci.Invoke(null);   
  25.     }   
  26. }   
  27. public class FactoryBoat:FactoryVehicle   
  28. {   
  29.     public IVehicle CreateVehicle()   
  30.     {   
  31.         return new Boat();   
  32.     }   
  33. }   
  34.   
  35. public class FactoryCar:FactoryVehicle   
  36. {   
  37.     public IVehicle CreateVehicle()   
  38.     {   
  39.         return new Car();   
  40.     }   
  41. }   
  42.   
  43. public interface FactoryVehicle   
  44. {   
  45.     IVehicle CreateVehicle();   
  46.   
  47. }   
  48. public interface IVehicle   
  49. {   
  50.     void go();   
  51. }   
  52.   
  53. public class Car:IVehicle   
  54. {   
  55.     public void go()   
  56.     {   
  57.         Console.WriteLine("car");   
  58.     }   
  59. }   
  60.   
  61. public class Boat:IVehicle   
  62. {   
  63.     public void go()   
  64.     {   
  65.         Console.WriteLine("boat");   
  66.     }   
  67. }  

转帖:http://anysky131.iteye.com/blog/234250

【上篇】
【下篇】

抱歉!评论已关闭.