设计模式学习笔记(工厂方法模式)

来源:互联网 发布:5g网络手机有哪些 编辑:程序博客网 时间:2024/05/16 23:49

转载自:http://www.impeng.org/factory-method.html

工厂方法模式属于创建型模式,即负责对象的创建。

为什么要有工厂?工厂的作用是将对象的创建和调用分离开来,对象的创建由工厂负责。因为在很多时候,对象的创建并不是new一个这么简单,其中可能会包含很多初始化函数。如果用传统的new方法实例化对象,当需要多次实例化时,会造成大量代码重复;而有工厂存在时,调用者只需要向工厂发出请求,工厂即返回所需对象,并且对调用者屏蔽了对象创建的细节,从而可以让调用者只需关注对象的使用,而不是其创建上。

要了解工厂方法模式(FactoryMethod),我们首先需要了解简单工厂(SimpleFactory,不是一种模式):

简单工厂可以概括为一句话:通过向工厂的产品创建方法中传入不同的参数,工厂返回相应的产品实例

  1. package com.csufox.SimpleFactory;       
  2.       
  3. interface Car {  //定义了Car接口       
  4.     public void start();  //抽象方法:启动       
  5. }       
  6.       
  7. class BMW implements Car {  //宝马车,实现了Car接口       
  8.     public void start() {       
  9.         System.out.println("BMW启动.");       
  10.     }       
  11. }       
  12.       
  13. class Benz implements Car {  //奔驰车,实现了Car接口       
  14.     public void start() {       
  15.         System.out.println("Benz启动.");       
  16.     }       
  17. }       
  18.       
  19. class CarFactory {  //车的工厂,根据不同的参数生产不同的Car的实例       
  20.     private CarFactory(){}   //私有构造函数可以防止用new的方式创建工厂       
  21.     public static Car create(String carName){       
  22.         if(carName.equals("BMW")){       
  23.             return new BMW();       
  24.         }       
  25.         else {       
  26.             return new Benz();       
  27.         }       
  28.     }       
  29. }       
  30.       
  31. public class SimpleFactory {       
  32.     public static void main(String[] args) {       
  33.         Car car = CarFactory.create("BMW");  //通过传入相应参数,告知工厂应该生产什么产品       
  34.         car.start();       
  35.     }       
  36. }     

仔细观察上面的代码及注释,可以看出简单工厂的特点是:

  • 包含有抽象产品(Car类)、具体产品(BMW类, Benz类)和工厂(CarFactory类);
  • 工厂的构造函数对外不可见,通过一个静态的产品创建方法来创建产品;
  • 调用者通过向产品创建方法中传入不同的参数,来得到对应的产品实例。

但是,思考如下问题:当我们需要新增一个产品的时候(比如,需要增加Buick车),将需要在工厂的产品创建方法中新增一个判断分支,也就是说需要修改工厂类的源代码。这显然不符合软件工程中最重要的开放关闭原则(OCP,Open-Close Principle;对扩展开放,对修改关闭)。

如何解决这个矛盾?在SimpleFactory中,一个工厂负责了所有产品的创建,当需要新增产品时,需要修改工厂类,这显然难以实现可扩展。由于可扩展大都是由接口来实现的,那么我们就可以抽象出工厂的特性(比如都有产品的创建方法create()),形成接口CarFactory,然后通过具体的工厂(实现了接口)来生产对应的产品,一个工厂只负责一种产品的创建。

这样,当需要新增产品时,我们可以通过三个步骤实现:

  1. 编写好新增的产品类(Buick车,实现抽象接口Car);
  2. 创建一个BuickFactory,实现抽象接口CarFactory(即实现其create方法);
  3. 调用者创建BuickFactory的实例,生产对应的Buick车。

具体代码如下:

  1. package com.csufox.FactoryMethod;    
  2.    
  3. interface Car {  //定义了Car接口(抽象产品)    
  4.     public void start();  //抽象方法:启动    
  5. }    
  6.    
  7. class BMW implements Car {  //宝马车,实现了Car接口    
  8.     public void start() {    
  9.         System.out.println("BMW启动.");    
  10.     }    
  11. }    
  12.    
  13. class Benz implements Car {  //奔驰车,实现了Car接口    
  14.     public void start() {    
  15.         System.out.println("Benz启动.");    
  16.     }    
  17. }    
  18.    
  19. class Buick implements Car {  //别克车,实现了Car接口    
  20.     public void start() {    
  21.         System.out.println("Buick启动.");    
  22.     }    
  23. }    
  24.    
  25. interface CarFactory {  //定义了CarFactory接口(抽象工厂)    
  26.     public Car create();    
  27. }    
  28.    
  29. class BMWFactory implements CarFactory{  //宝马车工厂(具体工厂)    
  30.     public Car create(){    
  31.         return new BMW();    
  32.     }    
  33. }    
  34.    
  35. class BenzFactory implements CarFactory{  //奔驰车工厂(具体工厂)    
  36.     public Car create(){    
  37.         return new Benz();    
  38.     }    
  39. }    
  40.    
  41. class BuickFactory implements CarFactory{  //别克车工厂(具体工厂)    
  42.     public Car create(){    
  43.         return new Buick();    
  44.     }    
  45. }    
  46.    
  47. public class FactoryMethod {  //客户端(调用模块)    
  48.     public static void main(String[] args) {    
  49.         CarFactory factory = new BuickFactory();  //实例化一个具体工厂    
  50.         Car car = factory.create();  //具体工厂生产对应的具体产品    
  51.         car.start();  //具体产品(奔驰车)生产出来    
  52.     }    
  53. }   

由上可知,工厂方法模式具有以下的特点:

  • 包含有抽象产品(Car类)、具体产品(如Buick类)、抽象工厂(CarFactory类)、具体工厂(如BuickFactory类);
  • 工厂需要实例化,即存在默认构造函数;
  • 一个具体工厂只负责一个具体产品的生产。

由此可知,工厂方法模式很好地遵循了开闭原则,实现了程序的可扩展。如果有新的产品需要生产,只需要新建一个具体工厂(实现抽象工厂接口)来负责该产品的创建;由于所有代码都面向接口实现,调用者只需要知道具体工厂的名称即可(如代码中的new BuickFactory();),将具体产品(具体工厂)返回给抽象产品(抽象工厂),不需要修改被调用模块的源代码,调用模块也只需要修改具体工厂的类名,提高了可维护性。

另外,如果将具体工厂名称的信息通过Java反射机制IOC方式(如Spring)注入到客户端中,这样连调用处的代码也不用修改了,只需要在配置文件中修改一下配置信息就行了。这样,整个程序就实现了源代码完全无修改的可扩展


原创粉丝点击