现实生活中,原始社会自给自足(没有工厂),农耕社会小作坊(简单工厂,民间酒坊),工业革命流水线(工厂方法,自产自销),现代产业链工厂(抽象工厂,富士康)。我们的项目代码同样是由简到繁一步一步迭代而来的,但对于调用者来说,却越来越简单。

什么是工厂模式?

在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑工厂模式来代替。

注意:上述复杂对象值的是 ,类的构造函数参数过多等对类的构造有影响的情况,因为类的构造过于复杂,如果直接在其他业务类内使用,则两者的耦合过重,后续业务更改,就需要在引用该类的源代码内进行更改,光是查找所有的依赖就很消耗时间了,更别说要一个一个修改了。

工厂模式的定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。

工厂模式的目的是:使得创建对象和使用对象分离,并且客户端总是引用抽象工厂的抽象产品。>

创建对象的时候,不给客户端暴露创建的逻辑。

实现方式

按照实际业务场景划分,工厂模式有三种实现方式:

  • 简单工厂模式

  • 工厂方法模式

  • 抽象工厂模式

我们把被创建的对象称为 “产品”,把创建产品的对象称为 “工厂”。

我们以宝马车作为产品举例,现要制造 BMW320 和 BMW523两个系列的车。

不用工厂模式

 1 public class noFactory {
 2     public static void main(String[] args) {
 3         BMW320 bmw320 = new BMW320();
 4         BMW523 bmw523 = new BMW523();
 5  6     }
 7 }
 8  9 10 // 创建一个BMW320 类
11 class BMW320 {
12     public BMW320() {
13         System.out.println("制造 ---> BMW320");
14     }
15 }
16 17 // 创建一个 BMW523
18 class BMW523 {
19     public BMW523() {
20       System.out.println("制造 ---> BMW523");
21     }
22 }

不使用工厂模式,相当于所有的对象创建的时候都要去 new 的,在创建对象的时候,可能需要传递各种参数,管理各种业务逻辑。

简单工厂模式

 1 public class easyFactory {
 2     public static void main(String[] args) {
 3         Factory factory = new Factory();
 4         BMW BMW320 = factory.createBMW(320);
 5         BMW BMW523 = factory.createBMW(523);
 6  7     }
 8 }
 9 10 // 创建一个产品类
11     // 构建一个抽象工厂
12 abstract class BMW {
13     public BMW() {
14 15     }
16 }
17 18 class BMW32002 extends BMW {
19     public BMW32002() {
20         System.out.println("制造 ---> BMW320");
21     }
22 }
23 24 class BMW52302 extends BMW {
25     public BMW52302() {
26         System.out.println("制造 ---> BMW523");
27     }
28 }
29 30 // 创建一个工厂类
31 class Factory {
32     public BMW createBMW(int type) {
33         switch(type) {
34             case 320:
35                 return new BMW32002();
36             case 523:
37                 return new BMW52302();
38             default:
39                 break;
40         }
41         return null;
42     }
43 

首先我们先建立一个抽象类,以上面场景为例,这个抽象类就申报表所有宝马车系列的抽象,

下面会有不同的实现类,比如:BMW32002BMW52302

然后在创建工厂类,所有的对象创建都放在工厂里面去,通过逻辑判断,创建哪一个实例对象。

  • 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品;

  • 抽象产品角色:它一般是具体产品继承的父类或者实现的接口;

  • 具体产品角色:工厂类所创建的对象就是此实例的实例。在 Java 中由一个具体类实现。

工厂方法模式

什么是工厂方法模式?

工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。

工厂方法模式又称多态性工厂,即核心的工厂类就不再负责所有产品的创建,把具体的创建工作交给子类去做,核心类成为抽象工厂角色,仅仅给出具体子类必须实现的接口。

工厂 方法模式的组成
  • 抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在 Java 中它由抽象类或者接口来实现。

  • 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

  • 抽象产品角色 :它是具体产品继承的父类或者是实现的接口。在 Java 中一般有抽象类或者抽象接口来实现。

  • 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在 Java 中具体的类来实现。

    (开闭原则)当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码 。

还是以上面场景为例:

 1 // 客户类 高层调用
 2 public class factoryMethod {
 3     public static void main(String[] args) {
 4         FactoryBMW320 factoryBMW320 = new FactoryBMW320();
 5         BMW02 BMW320 = factoryBMW320.createBMW();
 6  7         FactoryBMW523 factoryBMW523 = new FactoryBMW523();
 8         BMW02 BMW523 = factoryBMW523.createBMW();
 9     }
10 }
11 12 // 创建产品类
13     // 抽象产品角色
14 abstract class BMW02 {
15     public BMW02() {
16 17     }
18 }
19 20 // 子类
21     // 具体产品角色
22 class BMW32003 extends BMW02 {
23     public BMW32003() {
24         System.out.println("制造 ----> BMW320");
25     }
26 }
27 class BMW52303 extends BMW02 {
28     public BMW52303() {
29         System.out.println("制造 ----> BMW523");
30     }
31 }
32 33 // 创建工厂类
34     // 抽象工厂角色
35 interface FactoryBMW {
36     BMW02 createBMW();
37 }
38     // 具体工厂角色
39 class FactoryBMW320 implements FactoryBMW {
40     @Override
41     public BMW02 createBMW(){
42         return new BMW32003();
43     }
44 }
45 class FactoryBMW523 implements FactoryBMW {
46     @Override
47     public BMW02 createBMW(){
48         return new BMW52303();
49     }
50 }

工厂方法模式其实就是不同的产品实现放到了不同的工厂里面,不会在放到一个工厂里面去,工厂创建类的过程,分开放在了不同的子类去实现。

抽象工厂模式

什么是抽象工厂模式?

前面讲解的工厂方法模式中考虑的是一类产品的生产,如汽车厂制造汽车、飞机场制造飞机等。

同种类称为同等级,也就是说,工厂方法模式只考虑同等级的产品。但是现实生活中,大都是综合型工厂,生产多等级(即多种类)的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调等。在我们的工作中也一样,我们的工程也是根据业务的复杂度不断的迭代出来的,刚开始的逻辑可能特别简单 ,直接 new 就好了,什么设计模式、方法都不需要用,但是,当业务逐渐变得复杂了,有一堆业务逻辑要创建一个对象,这时候可以使用简单工厂模式,把创建的逻辑扔到一个工厂里面去。当业务变得更加复杂,我们需要创建 A 产品还需要创建 B 产品,而且 A 产品、B 产品的创建区别还特别大,这时候就需要使用工厂方法模式,随着业务迭代,比如之前是制造汽车,但是现在还需要制造飞机,这时候就需要使用抽象工厂模式,也就是说造车的工厂和造飞机的工厂分开。

抽象工厂模式,是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无需指定所要产品的具体类就能得到不同等级的模式结构。

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

抽象工厂模式与工厂方法模式的比较
工厂方法模式抽象工厂 模式
针对的是一个产品等级结构 针对的是面向多个产品等级结构
一个抽象产品类 多个抽象产品类
可以派生出多个具体产品类 每个抽象产品类可以派生出多个具体产品类
一个抽象工厂类可以派生出多个具体工厂类 一个抽象工厂类,可以派生出多个具体工厂类
每个具体工厂类只能创建一个具体产品类 每个具体工厂类可以创建多个具体产品类的实例
案例

用抽象工厂模式 设计农场类

分析:农场中除了像畜牧场一样可以养动物,还可以培养植物,如养马、养奶牛、种蔬菜、种水果等。

本例用抽象工厂模式设计两个农场,一个是农场A用于养奶牛和种菜,一个是农场B用于养马和种水果。以在以上两个农场中定义一个生成动物的方法 newAnimal() 和一个培养植物的方法 newPlant()

对马类、牛类、蔬菜类和水果类等具体产品类,由于要显示它们的图像,所以它们的构造函数中用到了 JPanelJLabelImageIcon 等组件,并定义一个 show() 方法来显示它们。

客户端程序通过对象生成器类 ReadXML 读取 XML 配置文件中的数据来决定养什么动物和培养什么植物。

  1 package 抽象工厂模式;
  2   3 import javax.swing.*;
  4 import java.awt.*;
  5   6 public class abstractFactory {
  7     public static void main(String[] args) {
  8         try {
  9             Farm f;
 10             Animal a;
 11             Plant p;
 12             f = (Farm) ReadXML.getObject();
 13             a = f.newAnimal();
 14             p = f.newPlant();
 15             a.show();
 16             p.show();
 17         } catch (Exception e) {
 18             System.out.println(e.getMessage());
 19         }
 20     }
 21 }
 22  23 // 抽象产品类
 24     // 动物类
 25 interface Animal {
 26     public void show();
 27 }
 28  29 // 具体产品类
 30     // 马类
 31 class Horse implements Animal {
 32     // 创建一个滚动面板
 33     JScrollPane sp;
 34     // 创建一个面板容器
 35     JFrame jf = new JFrame("抽象工厂模式测试");
 36  37     // 创建构造方法
 38     public Horse() {
 39         // 用getContentPane()方法获得JFrame的内容面板
 40         Container contentPane = jf.getContentPane();
 41         // 面板组件,非顶层容器
 42             // 一个界面只有一个JFrame窗体组件,但可以有多个JPanel面板组件,
 43             // 而JPanel上也可以使用布局管理器,这样组合可以达到比较复杂的布局效果
 44         JPanel p1 = new JPanel();
 45         // setLayout是对当前组件设置为流式布局.
 46             // JPanel的默认布局是流式布局,JFrame的默认布局是BorderLayout边框布局.
 47             // GridLayout 网格布局
 48         p1.setLayout(new GridLayout(1, 1));
 49         // setBorder,设置此组件的边框
 50             // BorderFactory 设置花样边框
 51         p1.setBorder(BorderFactory.createTitledBorder("动物:马"));
 52         // 创建一个滚动面板
 53         sp = new JScrollPane(p1);
 54         contentPane.add(sp, BorderLayout.CENTER);
 55         JLabel l1 = new JLabel(new ImageIcon("工厂模式/抽象工厂模式/image/A_Cattle.jpg"));
 56         p1.add(l1);
 57         jf.pack();
 58         jf.setVisible(false);
 59         //用户点击窗口关闭
 60         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 61     }
 62  63     public void show() {
 64         jf.setVisible(true);
 65     }
 66 }
 67 //具体产品:牛类
 68 class Cattle implements Animal {
 69     JScrollPane sp;
 70     JFrame jf = new JFrame("抽象工厂模式测试");
 71     public Cattle() {
 72         Container contentPane = jf.getContentPane();
 73         JPanel p1 = new JPanel();
 74         p1.setLayout(new GridLayout(1, 1));
 75         p1.setBorder(BorderFactory.createTitledBorder("动物:牛"));
 76         sp = new JScrollPane(p1);
 77         contentPane.add(sp, BorderLayout.CENTER);
 78         JLabel l1 = new JLabel(new ImageIcon("工厂模式/抽象工厂模式/image/A_Cattle.jpg"));
 79         p1.add(l1);
 80         jf.pack();
 81         jf.setVisible(false);
 82         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用户点击窗口关闭
 83     }
 84     public void show() {
 85         jf.setVisible(true);
 86     }
 87 }
 88 //抽象产品
 89     // 植物类
 90 interface Plant {
 91     public void show();
 92 }
 93 //具体产品
 94     // 水果类
 95 class Fruitage implements Plant {
 96     JScrollPane sp;
 97     JFrame jf = new JFrame("抽象工厂模式测试");
 98     public Fruitage() {
 99         Container contentPane = jf.getContentPane();
100         JPanel p1 = new JPanel();
101         p1.setLayout(new GridLayout(1, 1));
102         p1.setBorder(BorderFactory.createTitledBorder("植物:水果"));
103         sp = new JScrollPane(p1);
104         contentPane.add(sp, BorderLayout.CENTER);
105         JLabel l1 = new JLabel(new ImageIcon("工厂模式/抽象工厂模式/image/P_Fruitage.jpg"));
106         p1.add(l1);
107         jf.pack();
108         jf.setVisible(false);
109         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用户点击窗口关闭
110     }
111     public void show() {
112         jf.setVisible(true);
113     }
114 }
115 //具体产品
116     // 蔬菜类
117 class Vegetables implements Plant {
118     JScrollPane sp;
119     JFrame jf = new JFrame("抽象工厂模式测试");
120     public Vegetables() {
121         Container contentPane = jf.getContentPane();
122         JPanel p1 = new JPanel();
123         p1.setLayout(new GridLayout(1, 1));
124         p1.setBorder(BorderFactory.createTitledBorder("植物:蔬菜"));
125         sp = new JScrollPane(p1);
126         contentPane.add(sp, BorderLayout.CENTER);
127         JLabel l1 = new JLabel(new ImageIcon("工厂模式/抽象工厂模式/image/P_Vegetables.jpg"));
128         p1.add(l1);
129         jf.pack();
130         jf.setVisible(false);
131         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用户点击窗口关闭
132     }
133     public void show() {
134         jf.setVisible(true);
135     }
136 }
137 //抽象工厂
138     // 农场类
139 interface Farm {
140     public Animal newAnimal();
141     public Plant newPlant();
142 }
143 //具体工厂
144     // 农场A
145 class SGfarm implements Farm {
146     public Animal newAnimal() {
147         System.out.println("新牛出生!");
148         return new Cattle();
149     }
150     public Plant newPlant() {
151         System.out.println("蔬菜长成!");
152         return new Vegetables();
153     }
154 }
155 //具体工厂
156     // 农场B
157 class SRfarm implements Farm {
158     public Animal newAnimal() {
159         System.out.println("新马出生!");
160         return new Horse();
161     }
162     public Plant newPlant() {
163         System.out.println("水果长成!");
164         return new Fruitage();
165     }
 1 package 抽象工厂模式;
 2  3 import javax.xml.parsers.*;
 4 import org.w3c.dom.*;
 5 import java.io.*;
 6  7 public class ReadXML {
 8     public static Object getObject() {
 9         try {
10             DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
11             DocumentBuilder builder = dFactory.newDocumentBuilder();
12             Document doc;
13             doc = builder.parse(new File("工厂模式/抽象工厂模式/config.xml"));
14             NodeList nl = doc.getElementsByTagName("className");
15             Node classNode = nl.item(0).getFirstChild();
16             String cName = "抽象工厂模式." + classNode.getNodeValue();
17             System.out.println("新类名:" + cName);
18             Class<?> c = Class.forName(cName);
19             Object obj = c.newInstance();
20             return obj;
21         } catch (Exception e) {
22             e.printStackTrace();
23             return null;
24         }
25     }
26 }
1 <?xml version="1.0" encoding="UTF-8"?>
2 <config>
3     <className>SGfarm</className>
4 </config>

抽象工厂模式通常适用于以下场景:

  1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。

  2. 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。

  3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。