一起学模式之抽象工厂

  • 2019 年 10 月 5 日
  • 筆記

前言

学习过简单工厂,工厂方法模式后,我们再来看下工厂模式中最后一个模式:抽象工厂模式。它是《设计模式》之一,并且被广泛应用在程序框架中。本文主要从以下方面进行:

  • 模式定义
  • 编码实践
  • 优劣分析
  • 场景应用

<!– more–>

正文

模式定义

首先我们来看下抽象工厂的定义:

维基百科 The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes

意思就是为创建一组有公共目标且独立的工厂提供接口, 而无需指定它们的具体类, 而具体工厂只负责生成对应的产品.

抽象工厂定义比较抽象,那该如何理解呢,这里我举个例子, 我们常用的计算机分为服务器和PC,具有共同的特性,比如CPU,内存,磁盘容量等等, 他们有着不同应用的场景和需求; 因此他们的制造细节和性能都是有所差别的,于是每个产品都由专门工厂来生成,服务器由服务器工厂来制造,PC由PC工厂来制造.由于制造流程是一致的,我们就把服务器工厂和PC工厂的制造流程统一抽象出来,作为一个规范,具体实现由这些工厂根据自己的产品去实现. 这样创建模式就是抽象工厂模式,不知你明白一点了没有,这里我用类图表示下来帮助理解.

下图为抽象模式的通用类图, 抽象工厂模式目的就是提供一个创建多个工厂类的工厂抽象类或者接口,而无需指定它们的具体类,去生成一组属于一个产品家族的产品. 这里产品家族就表示一类具有相互依赖,或者公共属性的产品线.比如上文例子中服务器工厂及产品,PC工厂及产品就是一个产品家族.

编码实践

现在我们就用代码实现上文的例子

  /**     * @author One     * @description 抽象工厂模式实战     * @date 2018/09/19     */    public class AbastractFactoryLab {        public static void main(String[] args) {            ComputerFactory computerFactory = new ServerComputerFactory("2.9GHz", "16GB");            Computer computer = computerFactory.createComputer();            System.out.println(computer.getClass().getSimpleName() + " config :" + computer);            //ServerComputer config :cpu: 2.9GHz, memory: 16GB            computerFactory = new PCComputerFactory("2.4GHz", "4GB");            computer = computerFactory.createComputer();            System.out.println(computer.getClass().getSimpleName() + " config :" + computer);            //PCComputer config :cpu: 2.4GHz, memory: 4GB        }    }      /**     * 计算机工厂接口,亦可以是抽象类     */    interface ComputerFactory {        Computer createComputer();    }      /**     * 服务器产品工厂类     */    class ServerComputerFactory implements ComputerFactory {        private String cpu;        private String memory;          ServerComputerFactory(String cpu, String memory) {            this.cpu = cpu;            this.memory = memory;        }          @Override        public Computer createComputer() {            return new ServerComputer(this.cpu, this.memory);        }    }      /**     * PC产品工厂类     */    class PCComputerFactory implements ComputerFactory {        private String cpu;        private String memory;          PCComputerFactory(String cpu, String memory) {            this.cpu = cpu;            this.memory = memory;        }          @Override        public Computer createComputer() {            return new PCComputer(this.cpu, this.memory);        }    }        /**     * 抽象产品类     */    abstract class Computer {        abstract String getCPU();          abstract String getMemory();          @Override        public String toString() {            return "cpu: " + getCPU() + ", memory: " + getMemory();        }    }      /**     * 服务器产品     */    class ServerComputer extends Computer {        private String cpu;        private String memory;          ServerComputer(String cpu, String memory) {            this.cpu = cpu;            this.memory = memory;        }          @Override        String getCPU() {            return this.cpu;        }          @Override        String getMemory() {            return this.memory;        }    }      /**     * PC产品     */    class PCComputer extends Computer {        private String cpu;        private String memory;          PCComputer(String cpu, String memory) {            this.cpu = cpu;            this.memory = memory;        }          @Override        String getCPU() {            return this.cpu;        }          @Override        String getMemory() {            return this.memory;        }    }

优劣分析

优势

  • 保证了封装性,使用接口和抽象,只要知道工厂类即可创建对应需要产品对象。
  • 内部实现产品族内的约束,对外部透明。
  • 面向接口开发,而不是实现,更加动态化。

缺点

横向扩展容易,纵向扩展困难;新增一个产品族,只要提供对应工厂就可以,但是产品族扩展困难,要新增一个新产品,就要在抽象类添加对应的生产方法,从而影响所有实现类。

场景应用

使用抽象工厂模式我们可以应对以下场景:

  • 运行时决定调用哪个产品类。
  • 构造具有很多依赖的复杂对象。
  • 对象构造逻辑易变且根据配置决定。

我们也可以参照抽象工厂模式在优秀源码里的使用:

  • javax.xml.parsers.DocumentBuilderFactory#newInstance()
  • javax.xml.transform.TransformerFactory#newInstance()
  • javax.xml.xpath.XPathFactory#newInstance()
  • org.springframework.beans.factory.FactoryBean#getObject()

结语

本文进一步学习了抽象工厂模式,从定义和案例源码出发去理解,掌握模式的优缺点和应用场景。 最后再考虑个问题:工厂方法和抽象工厂的差异是什么呢?在我看来,工厂方法模式解决的是一个工厂生产多个同类产品的问题,而抽象工厂让每个产品有对应工厂来生产,无须关心具体的产品类,就能从对应工厂处获得产品类。

参考

  • Factory Patterns – Abstract Factory Pattern:https://www.codeproject.com/Articles/1137307/Factory-Patterns-Abstract-Factory-Pattern
  • Abstract Factory Design Pattern in Java:https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java
  • Abstract Factory:http://java-design-patterns.com/patterns/abstract-factory/