工厂模式(Factory Pattern) 是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
简单来说就是创建一个工厂类,然后当调用者想要创建一个对象时,只需要告诉工厂类即可,由工厂类去创建对象,调用者无需知道是如何创建的,也不用自己去创建。
作用:
- 解耦:把对象的创建和使用的过程分开。由于创建过程都由工厂统一管理,所以发生业务逻辑变化(比如类名变了,构造方法变了),不需要找到所有需要创建对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。(使用工厂模式 + 配置文件可以更好地解除耦合)
- 降低代码重复。如果创建对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。我们可以这些创建对象的代码放到工厂里统一管理。既减少了重复代码,也方便以后对对象的创建过程的修改维护。比如要创建一个数据库实例,可以直接使用数据库工厂来获取,而不需要自己去初始化各种参数等信息。
简单工厂:美的空调、美的电冰箱、格力空调、格力电冰箱由 1 个工厂类生产,通过参数来创建不同的对象(使用 if else 或者反射)。如果想要增加一个产品(比如海尔空调),需要修改工厂类代码。工厂方法:美的空调、美的电冰箱、格力空调、格力电冰箱分别由 4 个工厂类生产(每个工厂类中只有一个方法)。如果想要增加一个产品(比如海尔空调),需要增加一个产品类和一个工厂类。抽象工厂:将产品分族,美的空调、美的电冰箱都属于美的产品,则由美的工厂类生产(此时一个类中有两方法),格力空调、格力电冰箱都属于格力产品,则由格力工厂类生产。如果想要增加一个产品族(比如海尔空调、海尔电冰箱),需要增加一个产品族类和一个工厂类。
① 简单工厂模式
简单工厂模式不属于 23 中设计模式之一,其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象。
简单工程模式包含的角色(要素):
- 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品 :实现或者继承抽象产品的子类
- 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
优点:封装了创建对象的过程。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码(可能有多个客户代码),如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”(即对扩展开放,对修改关闭)。
② 工厂方法模式
定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。
工厂方法模式包含的角色(要素):
- 抽象产品,定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口。
- 具体产品,实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
- 工厂接口,也可以叫创建器,申明工厂方法,通常返回一个 产品类型的实例对象。
- 工厂实现,或者叫创建器对象,覆盖工厂接口定义的工厂方法,返回具体的产品实例。
优点:满足开闭原则。扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以(不需要修改除客户端以外的代码);屏蔽了产品的具体实现,调用者只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;。
缺点:每一个产品都对应一个工厂类。类的个数容易过多,产生类爆炸。
③ 抽象工厂模式
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。
抽象工厂模式包含的角色(要素):
- 抽象工厂,用于声明生成抽象产品的方法(可能有多个抽象方法)
- 具体工厂,实现抽象工厂定义的方法,具体实现一系列产品对象的创建
- 抽象产品,定义一类产品对象的接口
- 具体产品,通常在具体工厂里,会选择具体的产品实现,来创建符合抽象工厂定义的方法返回的产品类型的对象。
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。