前言
前面介绍了简单工厂模式和工厂方法模式。但是这两种模式对应的工厂结构过于单一(一个工厂只能生产一种产品),不适应与一些复杂的工厂等级结构,强行使用会导致工厂类的职责过于繁重,违反单一职责原则。因此我们推出抽象工厂模式。
一、场景问题
A、B工厂分别生产联想和戴尔品牌的笔记本,其组件包括主板、屏幕、CPU、电源等,为了简化问题,我们定义笔记本的组件包含三种:主板、屏幕、电源,请设计程序模拟客户下单某一品牌的电脑。
二、解决方案
根据前面学习的工厂模式,我们很容易就可以设计出实现方案,这里我们假设使用工厂方法模式来实现。
1、工厂方法模式
这里我们只设计出UML
类图,代码就省略了,毕竟工厂方法模式较为简单,而且不是本文的重点。工厂方法的核心就是每种产品定义一个单独的工厂类进行创建。场景中有两种品牌、三类产品,所以一共有2*3=6
种不同的产品,因此对于6种不同的工厂类。
1.1、UML
类图
1.2、模式缺点分析
- 工厂类过多,导致系统过于臃肿复杂。每新增一个组件就需要增加大量的类增加系统的运行开销。
- 商品之间没有关联性,如果有组合需求就需要用户自己去组合,可能导致组合中的各组件不兼容。
2、抽象工厂模式
2.1、产品等级结构与产品族
在使用抽象工厂模式改进前,我们先了解两个重要的概念
-
产品等级结构
即产品的继承结构。例如上面的案例,主板是抽象类,其子类有联想主板和戴尔主板,则主板和具体品牌的主板构成了一个产品等级结构。同理屏幕和屏幕的子类也构成了一个产品等级。屏幕和主板是不同等级结构的产品
-
产品族
指的是由一个工厂生产的处于不等产品等级结构的一组产品。例如工厂A生产的联想屏幕、联想电池和联想主板就构成了一个产品族。
抽象工厂模式中,具体工厂不再是只创建一种产品,而是创建一个产品族,这样可以大大减少类的数量,简化系统复杂度。
2.2、UML
类图
2.3、代码演示
-
定义抽象产品接口和抽象工厂接口(接口或抽象类都可行)
-
抽象产品接口
//主板 public interface MainBoard { void show(); } //屏幕 public interface Screen { void show(); } //电池 public interface Battery { void show(); }
-
抽象工厂接口
public interface AbstractFactory { /** * 生产主板 * @author xianzilei **/ Mainboard createMainBoard(); /** * 生产屏幕 * @author xianzilei **/ Screen createScreen(); /** * 生产电池 * @author xianzilei **/ Battery createBattery(); }
-
-
定义具体产品类和具体工厂类
-
具体产品类
//联想主板 public class LenovoMainBoard implements MainBoard{ @Override public void show() { System.out.println("联想主板"); } } //戴尔主板 public class DellMainBoard implements MainBoard{ @Override public void show() { System.out.println("戴尔主板"); } } //联想屏幕 public class LenovoScreen implements Screen{ @Override public void show() { System.out.println("联想屏幕"); } } //戴尔屏幕 public class DellScreen implements Screen{ @Override public void show() { System.out.println("戴尔屏幕"); } } //联想电池 public class LenovoBattery implements Battery{ @Override public void show() { System.out.println("联想电池"); } } //戴尔电池 public class DellBattery implements Battery{ @Override public void show() { System.out.println("戴尔电池"); } }
-
具体工厂类
//联想工厂 public class LenovoFactory implements AbstractFactory{ @Override public MainBoard createMainboard() { return new LenovoMainBoard(); } @Override public Screen createScreen() { return new LenovoScreen(); } @Override public Battery createBattery() { return new LenovoBattery(); } } //戴尔工厂 public class DellFactory implements AbstractFactory { @Override public MainBoard createMainboard() { return new DellMainBoard(); } @Override public Screen createScreen() { return new DellScreen(); } @Override public Battery createBattery() { return new DellBattery(); } }
-
-
客户端测试
public static void main(String[] args) { //定义抽象层(这里也可以通过配置反射获取bean) AbstractFactory factory = new DellFactory(); //调用工厂类方法创建各类产品 MainBoard mainboard = factory.createMainboard(); Screen screen = factory.createScreen(); Battery battery = factory.createBattery(); mainboard.show(); screen.show(); battery.show(); }
三、模式概述
对于这种产品数量庞大,产品间存在相互关联关系的业务场景,抽象工厂模式就登场了。
1、模式定义
抽象工厂模式(Simple Factory Pattern):是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级,工厂方法模式只生产一种类型的商品,而抽象工厂模式则可以生产多个等级的产品。
2、模式结构
抽象工厂模式角色与工厂方法角色类似,一般包含如下角色
-
Abstract Factory
:抽象工厂角色抽象工厂的接口,定义工厂的创建方法,相对于工厂方法模式的区别是它可以定义多个生产产品的方法,即创建不同等级的产品。
-
Concrete Factory
:具体工厂角色用于实现抽象工厂中的多个创建方法,完成具体产品的创建
-
Product
:抽象产品角色抽象产品角色是所创建的所有对象的父类,负责描述同等级实例的公共接口(也可以是抽象类)
-
ConcreteProduct
:具体产品角色抽象产品角色的实现类,它与具体工厂之间是多对一的关系
3、模式结构图
4、优缺点
- 优点
- 分离接口和实现。客户端并不知道具体的实现,只知道接口。
- 易切换产品簇。上面的案例,想要切换联想品牌的产品,直接修改配置返回联想工厂实现即可。
- 缺点
- 不易添加产品。当给产品簇添加一个产品(即添加产品等级结构)时,此时就需要修改抽象工厂接口,添加个创建该产品的方法,同时所有的实现类都需要被迫实现该方法。
- 类层次较为复杂
5、使用场景
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
- 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
四、模式扩展
1、模式的退化
- 当抽象工厂中的每一个工厂类都只创建一个商品,即只存在一个产品等级结构时,抽象工厂模式就会退化为工厂方法模式。
- 当抽象工厂与具体工厂合并,只提供一个统一的工厂来创建产品对象,并将创建产品的方法设置为静态方法,抽象工厂模式就会退化为简单工厂模式。