JAVA设计模式(2) —<创建型>抽象工厂模式(Abstract Factory)

来源:互联网 发布:火球理财java面试题 编辑:程序博客网 时间:2024/06/07 06:06

1 定义:

抽象工厂模式(Abstract Factory)

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.(为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。)

 1.1 通用类图:

 

主要类图-1


更体现抽象工厂实质的类图及说明

 (1).AbstractFactory:声明一个创建抽象产品对象的接口。        

 (2).CreateFactory:实现创建具体产品对象的操作。        

 (3).AbstractProduct:为一类产品对象声明接口。        

 (4).CreateProduct:定义一个将被相应具体工厂创建的产品对象,以实现AbstractProduct接口。        

 (5).仅使用AbstractFactory和AbstractProduct类声明的接口。

1.2 通用代码:

抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。我们来看看抽象工厂的通用源代码,首先有两个互相影响的产品线(也叫做产品族,产品种类),例如汽车的左侧门和右侧门,这两个应该是数量相等的——两个对象之间的约束,每个型号的车门都是不一样的,这是产品等级结构约束的。

 类图如下:

[java] view plaincopy
  1. public abstract class AbstractProductA {          
  2.          //每个产品共有的方法  
  3.          public void shareMethod(){                
  4.          }  
  5.           
  6.          //每个产品相同方法,不同实现  
  7.          public abstract void doSomething();  
  8. }  
  9.    
  10. public abstract class AbstractProductB {          
  11.          //每个产品共有的方法  
  12.          public void shareMethod(){                
  13.          }  
  14.           
  15.          //每个产品相同方法,不同实现  
  16.          public abstract void doSomething();  
  17. }  
  18.    
  19. public class ProductA_Level_1 extendsAbstractProductA {  
  20.          @Override  
  21.          public void doSomething() {  
  22.                    System.out.println("产品A等级1的实现方法");  
  23.          }  
  24. }  
  25.    
  26. public class ProductA_Level_2 extendsAbstractProductA {  
  27.          @Override  
  28.          public void doSomething() {  
  29.                    System.out.println("产品A等级2的实现方法");  
  30.          }  
  31. }  
  32.    
  33. public class ProductB_Level_1 extendsAbstractProductB {  
  34.          @Override  
  35.          public void doSomething() {  
  36.                    System.out.println("产品B等级1的实现方法");  
  37.          }  
  38. }  
  39.    
  40. public class ProductB_Level_2 extendsAbstractProductB {  
  41.          @Override  
  42.          public void doSomething() {  
  43.                    System.out.println("产品B等级2的实现方法");  
  44.          }  
  45. }  
  46. public abstract class AbstractCreator {  
  47.    
  48.          //创建A产品家族  
  49.          public abstract AbstractProductA createProductA();  
  50.           
  51.          //创建B产品家族  
  52.          public abstract AbstractProductB createProductB();  
  53. }  
  54.    
  55. public class Creator_Level_1 extends AbstractCreator {  
  56.           
  57.          //只生产产品等级为1的A产品  
  58.          public AbstractProductA createProductA() {    
  59.                    return new ProductA_Level_1();  
  60.          }  
  61.    
  62.          //只生产铲平等级为1的B产品  
  63.          public AbstractProductB createProductB() {  
  64.                    return new ProductB_Level_1();  
  65.          }  
  66. }  
  67.    
  68. public class Creator_Level_2 extendsAbstractCreator {  
  69.           
  70.          //只生产产品等级为2的A产品  
  71.          publicAbstractProductA createProductA() {    
  72.                    return new ProductA_Level_2();  
  73.          }  
  74.    
  75.          //只生产铲平等级为2的B产品  
  76.          public AbstractProductB createProductB() {  
  77.                    return new ProductB_Leve

2 优点

2.1 封装性

每个产品的实现类不是高层模块要关心的,它要关心的是:接口,抽象,它不关心对象是如何创建出来的,这是由工厂类创建的,只要知道工厂类是谁,我就能创建出一个需要的对象,省时省力。

2.2 产品族内的约束为非公开状态。

在抽象工厂模式中应该有这样一个约束:约束不同等级产品的生产比例。而这样的生产过程对调用工厂类的高层模式来说是透明的,它不需要知道这个约束,它就是要一个这样的产品,具体的产品族内的约束是在工厂内实现的

3 缺点

抽象工厂模式的最大缺点就是产品族扩展非常困难,为什么这么说呢?我们以通用代码为例,如果要增加一个产品C,也就是说有产品家族由原来的2个,增加到3个,看看我们的程序有多大改动吧!抽象类AbstractCreator要增加一个方法createProductC(),然后,两个实现类都要修改,想想看,这在项目中的话,还这么让人活!严重违反了开闭原则,而且我们一直说明抽象类和接口是一个契约,改变契约,所有与契约有关系的代码都要修改,这段代码叫什么?叫“有毒代码”,——只要这段代码有关系,就可能产生侵害的危险!

  

4 应用场景

抽象工厂模式的使用场景定义非常简单:一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式,什么意思呢?例如一个文本编辑器和一个图片处理器,都是软件实体,但是*nix下的文本编辑器和WINDOWS下的文本编辑器虽然功能和界面都相同,但是代码实现是不同的,图片处理器也是类似情况,也就是具有了共同的约束条件:操作系统类型,于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器

 

5 注意事项

在上述缺点论述中,提到抽象工厂模式的产品族扩展比较困难,但是要清楚产品族扩展困难,而不是产品等级。在该模式下,产品等级是非常容易扩展的,增加一个产品等级,只要增加一个工厂类负责新增加出来的产品生产任务即可。也就是说横向<产品等级>扩展容易纵向<产品族>扩展困难横向扩展上来讲,抽象工厂模式还是符合开闭原则的。

 

6 扩展

6.1 抽象工厂模式与工厂方法模式的区别

    抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。

    他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。         

     在抽象工厂模式中,有一个产品族的概念:所谓的产品族是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构 。

我们拿生产汽车的例子来说明他们之间的区别。

        在上面的类图中,两厢车和三厢车称为两个不同的等级结构;而2.0排量车和2.4排量车则称为两个不同的产品族。再具体一点,2.0排量两厢车和2.4排量两厢车属于同一个等级结构,2.0排量三厢车和2.4排量三厢车属于另一个等级结构;而2.0排量两厢车和2.0排量三厢车属于同一个产品族,2.4排量两厢车和2.4排量三厢车属于另一个产品族。

        明白了等级结构和产品族的概念,就理解工厂方法模式和抽象工厂模式的区别了,如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式如果工厂的产品来自多个等级结构,则属于抽象工厂模式。在本例中,如果一个工厂模式提供2.0排量两厢车和2.4排量两厢车,那么他属于工厂方法模式;如果一个工厂模式是提供2.4排量两厢车和2.4排量三厢车两个产品,那么这个工厂模式就是抽象工厂模式,因为他提供的产品是分属两个不同的等级结构。当然,如果一个工厂提供全部四种车型的产品,因为产品分属两个等级结构,他当然也属于抽象工厂模式了。


7 范例

7.1 华为 高低端手机

(高低等级、功能机智能机)

 类图如下:


[java] view plaincopy
  1. package _03_AbstractFactory;  
  2.   
  3. public interface Phone {  
  4.     //获取手机类别  
  5.     public void getKind();  
  6.     //获取手机功能特性  
  7.     public void getFunctions();  
  8.     //获取手机等级  
  9.     public void getLevel();  
  10. }  
  11.   
  12. public abstract class AbstractFeaturePhone implements Phone{  
  13.     public void getKind() {  
  14.         System.out.println("我是功能机! ");  
  15.     }     
  16.   
  17.     public void getFunctions() {  
  18.         System.out.println("我只有有限的功能!");  
  19.     }  
  20. }  
  21.   
  22. public class FPhone_Level_High extends AbstractFeaturePhone{  
  23.     @Override  
  24.     public void getLevel() {  
  25.         System.out.println("高端机");  
  26.     }     
  27. }  
  28.   
  29. public class FPhone_Level_Low extends AbstractFeaturePhone{  
  30.     @Override  
  31.     public void getLevel() {  
  32.         System.out.println("低端机");  
  33.     }     
  34. }  
  35.   
  36.   
  37.   
  38. public abstract class AbstractSmartPhone implements Phone{  
  39.   
  40.     public void getKind() {  
  41.         System.out.println("我是智能机! ");  
  42.     }  
  43.   
  44.     public void getFunctions() {  
  45.         System.out.println("我有无限多的功能!");  
  46.     }  
  47. }  
  48.   
  49. public class SPhone_Level_High extends AbstractSmartPhone{  
  50.     @Override  
  51.     public void getLevel() {  
  52.         System.out.println("高端机");  
  53.     }     
  54. }  
  55.   
  56. public class SPhone_Level_Low extends AbstractSmartPhone{  
  57.     @Override  
  58.     public void getLevel() {  
  59.         System.out.println("低端机");  
  60.     }     
  61. }  
  62.   
  63. public abstract class PhoneFactory {  
  64.     public abstract Phone createFeaturePhone();  
  65.     public abstract Phone createSmartPhone();  
  66. }  
  67.   
  68. public class Creator_Level_High extends PhoneFactory{  
  69.     public Phone createFeaturePhone(){  
  70.         return new FPhone_Level_High();       
  71.     }  
  72.     public Phone createSmartPhone() {  
  73.         return new SPhone_Level_High();   
  74.     }  
  75. }  
  76.   
  77. public class Creator_Level_Low extends PhoneFactory{  
  78.     public Phone createFeaturePhone(){  
  79.         return new FPhone_Level_Low();        
  80.     }  
  81.     public Phone createSmartPhone() {  
  82.         return new SPhone_Level_Low();    
  83.     }  
  84. }  
  85.   
  86. public class Client {  
  87.     public static void main(String[] args) {  
  88.         //第一条产线,产高端机  
  89.         PhoneFactory pfh = new Creator_Level_High();  
  90.         //第二条产线,产高端机  
  91.         PhoneFactory pfl = new Creator_Level_Low();  
  92.           
  93.         Phone sh = pfh.createSmartPhone();  
  94.         sh.getLevel();  
  95.         sh.getKind();  
  96.         sh.getFunctions();  
  97.           
  98.         Phone fl = pfl.createFeaturePhone();  
  99.         fl.getLevel();  
  100.         fl.getKind();  
  101.         fl.getFunctions();  
  102.     }  
  103. }  

结果:

高端机
我是智能机! 
我有无限多的功能!
低端机
我是功能机! 
我只有有限的功能!

7.2 选择组装电脑的配件

装机工程师要组装电脑对象,需要一系列的产品对象,比如CPU、主板等,于是创建一个抽象工厂给装机工程师使用,在这个抽象工厂里面定义抽象的创建CPU和主板的方法,这个抽象工厂就相当于一个抽象的装机方案,在这个装机方案里面,各个配件是能够相互匹配的。

每个装机的客户,会提出他们自己的具体装机方案,或者是选择已有的装机方案,相当于为抽象工厂提供了具体的子类,在这些具体的装机方案类里面,会创建具体的CPU和主板实现对象。


1、先看看CPU和主板的接口

CPU接口定义的示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * CPU的接口 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public interface CPUApi {  
  7.   
  8.     /** 
  9.      * 示意方法,CPU具有运算的功能 
  10.      */  
  11.     public void calculate();  
  12. }  

主板接口定义的示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 主板的接口 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public interface MainBoardApi {  
  7.   
  8.     /** 
  9.      * 示意方法,主板都具有安装CPU的功能 
  10.      */  
  11.     public void installCPU();  
  12. }  

2、具体的CPU实现

Intel CPU实现示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Intel 的 CPU实现 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public class IntelCPU implements CPUApi {  
  7.   
  8.     /** 
  9.      * CPU的针脚数目 
  10.      */  
  11.     private int pins = 0;  
  12.       
  13.     /** 
  14.      * 构造方法,传人CPU的针脚数目 
  15.      * @param pins 
  16.      */  
  17.     public IntelCPU(int pins) {  
  18.         this.pins = pins;  
  19.     }  
  20.   
  21.     @Override  
  22.     public void calculate() {  
  23.         System.out.println("now in Intel CPU,pins="+pins);  
  24.     }  
  25.   
  26. }  
AMD CPU实现示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * AMD 的 CPU实现 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public class AMDCPU implements CPUApi {  
  7.   
  8.     /** 
  9.      * CPU的针脚数目 
  10.      */  
  11.     private int pins = 0;  
  12.       
  13.     /** 
  14.      * 构造方法,传人CPU的针脚数目 
  15.      * @param pins 
  16.      */  
  17.     public AMDCPU(int pins) {  
  18.         this.pins = pins;  
  19.     }  
  20.   
  21.     @Override  
  22.     public void calculate() {  
  23.         System.out.println("now in AMD CPU,pins="+pins);  
  24.     }  
  25.   
  26. }  

3、具体的主板实现

技嘉主板实现的示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 技嘉主板 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public class GAMainBoard implements MainBoardApi {  
  7.   
  8.     /** 
  9.      * CPU插槽的孔数 
  10.      */  
  11.     private int cpuHoles = 0;  
  12.       
  13.     /** 
  14.      * 构造方法,传人CPU插槽的孔数 
  15.      * @param cpuHoles 
  16.      */  
  17.     public GAMainBoard(int cpuHoles) {  
  18.         this.cpuHoles = cpuHoles;  
  19.     }  
  20.   
  21.     @Override  
  22.     public void installCPU() {  
  23.         System.out.println("now in GAMainBoard,cpuHoles="+cpuHoles);  
  24.     }  
  25.   
  26. }  

华硕主板实现的示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 华硕主板 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public class ASUSMainBoard implements MainBoardApi {  
  7.   
  8.     /** 
  9.      * CPU插槽的孔数 
  10.      */  
  11.     private int cpuHoles = 0;  
  12.       
  13.     /** 
  14.      * 构造方法,传人CPU插槽的孔数 
  15.      * @param cpuHoles 
  16.      */  
  17.     public ASUSMainBoard(int cpuHoles) {  
  18.         this.cpuHoles = cpuHoles;  
  19.     }  
  20.   
  21.     @Override  
  22.     public void installCPU() {  
  23.         System.out.println("now in ASUSMainBoard,cpuHoles="+cpuHoles);  
  24.     }  
  25.   
  26. }  

4、抽象工厂的定义,示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 抽象工厂的接口,声明创建抽象产品对象的操作 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public interface AbstractFactory {  
  7.       
  8.     /** 
  9.      * 创建CPU的对象 
  10.      * @return 
  11.      */  
  12.     public CPUApi createCPUApi();  
  13.       
  14.     /** 
  15.      * 创建主板的对象 
  16.      * @return 
  17.      */  
  18.     public MainBoardApi createMainBoardApi();  
  19. }  

5、再看看抽象工厂的实现对象,也就是具体的装机方案对象。

方案1:的实现,示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 装机方案1:AMD CPU + 华硕主板 
  3.  * 这里创建CPU和主板对象的时候,是对应的,能匹配上的 
  4.  * @author FX_SKY 
  5.  * 
  6.  */  
  7. public class Schema1 implements AbstractFactory {  
  8.   
  9.     @Override  
  10.     public CPUApi createCPUApi() {  
  11.         return new AMDCPU(956);  
  12.     }  
  13.   
  14.     @Override  
  15.     public MainBoardApi createMainBoardApi() {  
  16.         return new ASUSMainBoard(956);  
  17.     }  
  18.   
  19. }  

方案2:的实现,示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 装机方案2:Intel CPU + 技嘉主板 
  3.  * 这里创建CPU和主板对象的时候,是对应的,能匹配上的 
  4.  * @author FX_SKY 
  5.  * 
  6.  */  
  7. public class Schema2 implements AbstractFactory {  
  8.   
  9.     @Override  
  10.     public CPUApi createCPUApi() {  
  11.         return new IntelCPU(1156);  
  12.     }  
  13.   
  14.     @Override  
  15.     public MainBoardApi createMainBoardApi() {  
  16.         return new GAMainBoard(1156);  
  17.     }  
  18.   
  19. }  

6、装机工程师类的实现,示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 装机工程师的类 
  3.  * @author FX_SKY 
  4.  * 
  5.  */  
  6. public class ComputerEngineer {  
  7.   
  8.     /** 
  9.      * 定义组装电脑需要的CPU 
  10.      */  
  11.     private CPUApi cpu;  
  12.     /** 
  13.      * 定义组装电脑需要的主板 
  14.      */  
  15.     private MainBoardApi mainBoard;  
  16.       
  17.     public void makeComputer(AbstractFactory schema){  
  18.         //1、首先准备好装机所需要的配件  
  19.         prepareHardwares(schema);  
  20.         //2、组装电脑  
  21.         //3、测试电脑  
  22.         //4、交付客户  
  23.     }  
  24.   
  25.     private void prepareHardwares(AbstractFactory schema) {  
  26.         //使用抽象工厂来获取相应的接口对象  
  27.         this.cpu = schema.createCPUApi();  
  28.         this.mainBoard = schema.createMainBoardApi();  
  29.           
  30.         //测试一下配件是否好用  
  31.         this.cpu.calculate();  
  32.         this.mainBoard.installCPU();  
  33.     }  
  34. }  

6、客户端使用抽象工厂,示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class Client {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         //创建装机工程师对象  
  8.         ComputerEngineer cm = new ComputerEngineer();  
  9.         //客户选择并创建需要使用的装机方案对象  
  10.         Schema1 schema1 = new Schema1();  
  11.         //告诉装机工程师自己的装机方案,让装机工程师组装电脑  
  12.         cm.makeComputer(schema1);  
  13.     }  
  14.   
  15. }  
0 0
原创粉丝点击