工厂模式
工厂模式
下面将介绍几种常用的工厂模式
简单工厂模式
类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。其专门定义了一个类来负责创建其他类的实例,被创建的实例通常都具有相同的父类。

模式动机
以一个简单地软件应用场景引入:一个软件系统可以提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等),这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以呈现不同的外观,如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。
应用
简单工厂模式只包含三个角色:
- 工厂角色Factory
- 抽象产品角色Product
- 具体产品角色ConcreteProduct
举个例子,现在有问题代码如下

用简单工厂方法进行重构


优点
- 简单工厂模式将对象的创建和对象本身的业务逻辑分离,以降低系统耦合度,使得修改任何一方都相对容易。
- 工厂方法是静态的,很好调用,不需要实例化
- 需要一个产品,只需要传入正确的参数即可获取目标对象实例,不需要知道创建的细节(比如不用记忆复杂的类名)
- 客户端只负责“消费”产品,免除了创建的责任
- 传入的参数甚至不需要写在客户端代码里,可以放到xml等配置文件中,这样可以不修改任何客户端代码的情况下添加新产品
缺点
- 工厂类的职责过重,如果需要添加新的产品需要去修改已实现的具体工厂类的源代码,违反了开闭原则。
- 同样,由于工厂类聚集了所有创建逻辑,一旦出问题整个系统都会被影响
- 扩展困难,如果产品类型过多或频繁添加新产品,工厂类难以维护
实例:权限管理

实例:JDK类库
java.text.DateFormat
public final static DateFormat getDateInstance(); |
工厂方法模式
类创建型模式。
模式动机
作为对简单工厂模式的改进,工厂方法模式不会有一个专门的工程类来负责所有产品的创建,而是将具体产品的创建交给专门的工厂子类。这样就只需要先定义一个抽象工厂类,再定义具体的工厂类去实现这个抽象工厂类负责创建不同的具体产品。
这样的抽象化就允许在不修改任何具体类的前提下添加新的产品(通过添加新产品 + 新工厂即可)。

实例:日志记录器
某系统日志记录器要求支持多种日志记录方式,如文件记录、数据库记录等,且用户可以根据要求动态选择日志记录方式,现使用工厂方法模式设计该系统

优点
- 工厂方法不仅用来创建客户需要的产品,并且隐藏了那种产品将被实例化,用户只需要关心产品对应的工厂即可,甚至不需要知道产品的类名(用抽象产品引用即可)
- 工厂可以自主确定创建何种产品对象,如何创建则完全封装在具体工厂内部
- 符合开闭原则
缺点
- 每次添加新产品需要编写新的产品类和对应的具体工厂类,系统中类的数目成对增长,复杂度变高,编译负担变大
- 增加了系统的抽象性和理解难度,并且实现时可能会用到DOM、反射等技术,增加实现难度
适用场景
- 一个类不知道它所需要的对象的类
- 一个类通过其子类来指定创建哪个对象
- 将创建对象的任务委托给多个工厂子类中的一个,客户端使用时无需关心哪一个工厂子类创建产品子类,运行时再动态指定
抽象工厂模式
对象创建型模式
模式动机
工厂方法模式中一个工厂只能创建一种产品,有时候我们需要一个工厂提供多种产品,而不是单一的产品对象。
为了能理解为什么我们会有这样的需求,并且清晰的区分抽象工厂和工厂模式,引入几个基本概念:
- 产品等级结构:即产品的继承结构,比如抽象电视机和具体品牌的电视机(TCL、海尔等)
- 产品族:同一个工厂生产的一组不同产品,它们分别位于各自产品的某个等级结构中,比如海尔工厂生产的海尔电视机、海尔电冰箱等

当一个系统所提供的工厂生产的具体产品并不是一个单独的产品,而是多个位于上述不同产品等级结构中产品对应的的一个产品族时,就需要抽象工厂。比如一个具体工厂既需要生产具体电视机又需要生产具体电冰箱。
与工厂方法模式区分
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构
结构
抽象工厂提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

抽象工厂模式包含如下角色:
- 抽象工厂AbstractFactory
- 具体工厂ConcreteFactory
- 抽象产品AbstractProduct
- 具体产品ConcreteProduct
典型代码如下:
public abstract class AbstractFactory { |
public class ConcreteFactory1 extends AbstractFactory { |
示例:操作系统交互组件

示例:电器工厂

示例:数据库操作工厂
某系统为了改进数据库操作的性能,自定义数据库连接对象Connection和语句对象Statement,可针对不同类型的数据库提供不同的连接对象和语句对象,如提供Oracle或SQL Server专用连接类和语句类,而且用户可以通过配置文件等方式根据实际需要动态更换系统数据库。

优点
- 隔离了具体类的生成,客户并不知道什么被创建,因此更改具体工厂的实例很方便,因为大家都实现同一个抽象工厂接口,接口中的公共接口也都被实现了,只需要根据需求选择特定工厂生产的产品即可
- 高内聚低耦合。相同产品族中的产品都在同一个工厂(一个产品族)中,能够保证客户端始终只使用同一个产品族中的对象
- 增加新的工厂和产品族的时候很方便,这时候是符合开闭原则的
缺点
难以往已有工厂中扩展新产品,换言之,这时候是违反开闭原则的,即开闭原则的倾斜性。通俗的说,很容易添加一个全新的品牌,但是已有品牌想做跨界很难。
适用场景
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,不只是对于抽象工厂模式,所有工厂模式都是如此
- 系统中产品族(品牌)数目 ,每次只使用其中某一个产品族(品牌)的产品
- 属于同一个产品族的产品将在一起被使用
- 系统提供一个产品类的库(一个全局统一的抽象产品接口,对应一个产品等级结构,所有属于这个产品等级结构的具体产品都去实现它),所有产品以同样的接口被引用,从而使客户端不依赖具体实现
(•‿•)