【实战指南】设计模式 - 工厂模式

简介: 工厂模式是一种面向对象设计模式,通过定义“工厂”来创建具体产品实例。它包含简单工厂、工厂方法和抽象工厂三种形式,分别适用于不同复杂度的场景。简单工厂便于理解但扩展性差;工厂方法符合开闭原则,适合单一类型产品创建;抽象工厂支持多类型产品创建,但不便于新增产品种类。三者各有优缺点,适用于不同设计需求。

工厂模式是一种面向对象设计模式,定义了 工厂 的概念,软件设计时抽象产品派生出产品子类,具体的产品实例由 工厂 创建,用户从 工厂 申请需要的产品实例来使用。

简单工厂

简单工厂的概念并不存在于23种设计模式之中,学习的过程中发现其实现原理有助于理解本文后面两种设计模式。这里就列举出来。

其实现原理是,先抽象出产品的基类,然后由基类派生出各种产品子类。工厂 仅需要设计业务,由输入参数来确定创建哪种产品实例 注1

场景列举:

假设一个场景: 某手机厂商旗下有Mate、Nova和P等品牌,不同的品牌功能相同但参数有所差异,工厂拥有生产所有品牌手机的能力。当Mate品牌发布新机,工厂需要生产Mate品牌;类似的,当其他品牌发布新机,工厂也需要生产其他品牌。那么从面向对象设计的角度,如何将此场景设计出来呢?

解决: 首先将类定义出来,涉及到Mate、Nova、P和工厂类,工厂的接口返回手机的实例。那么问题来了,从软件角度来思考,工厂的一个接口只能返回一种类的实例,如何让一个接口返回多个不同类的实例呢?C++基类虚函数可以解决这个问题注2。因此将Mate、Nova和P抽象出一个基类CPhone,工厂接口类型指定为CPhone *。加入逻辑判断,达到不同的参数返回不同的手机实例效果。

类图

使用方法: 当需要生产某个品牌手机时,只需要在工厂方法getPhoneInstance指定product即可获取到某品牌实例。

缺点:

  • 当增加新的手机品牌时,需要更改工厂方法getPhoneInstance来兼容新的品牌,不符合开闭原则注3

工厂方法

由于简单工厂的缺点是不可忽视的,因此对简单工厂进行优化从而产生 工厂方法 的概念。从简单方法的类图中可以发现,工厂方法getPhoneInstance需要优化。

解决:由多个工厂子类替换掉参数的做法。将工厂类派生出多个工厂子类,一个工厂子类对应一个产品子类。如此一来,增加一个产品时,仅需要增加一个工厂子类即可,不需要对之前的逻辑进行修改。

类图:

使用方法: 当需要生产某种品牌时,用户只需要由new对应的工厂子类实例,由getPhoneInstance获取此品牌实例。若增加新品牌,需要工厂派生新的工厂子类,对应的产品派生出新的产品子类,由新的工厂实例getPhoneInstance返回新的产品实例即可。

缺点:

  • 当出现新的产品时,就需要发布新的工厂子类,长此以往工厂实例会越来越庞大,对使用者不友好。

抽象工厂

工厂方法多用于同一类型的产品生产,即仅存在一个抽象产品基类。假设业务需要,工厂要增加新产品(Watch)。此时 工厂方法 的设计无法满足需求,由此又提出了抽象工厂的概念。

解决方法: 新增产品基类CWatch派生出产品子类CHwGt2、CHwGt2Pro,同时在工厂基类中增加获取该子类实例的接口。如此一来,每个工厂都具备生产CPhone和CWatch的能力。

类图:

使用方法:与工厂方法类似,先new出对应的工厂子类实例,然后调用getPhoneInstance和getWatchInstance获取对应的产品实例。

缺点:

  • 当新增一个不同于已存在的产品种类时(如notebook),需要在工厂基类及所有子类中增加getNoteBookInstance的接口。若存在大量的工厂子类,这种操作是存在风险的,也不符合开闭原则 注3

总结

  • 工厂方法属于创建型模式,主要用于规范类实例的创建。
  • 简单工厂用法简单但是不符合开闭原则,设计中不要采用此种方式。工厂方法适合于单一类型的产品实例。抽象工厂适合于创建多个已知类型产品实例,不适用于增加新的产品类型。
  • 几种工厂方式都存在一定缺陷,在长期使用过程中会创建过多子类,可能会造成代码难以维护。对于少数量的产品,是很实用的技巧。
  • 还需要寻找有没有更好的技巧能够避免工厂存在的缺陷。
  • 代码:https://gitee.com/dongxianghd/DesignMode/tree/master/FactoryMode

[ 注1]  一个方法返回不同的实例。

[ 注2]  C++继承中可以将基类虚函数的重写,基类类型会调用子类重写的虚函数。

[ 注3]  开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。

相关文章
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
12月前
|
设计模式 安全 Java
Java设计模式(一):单例模式与工厂模式
本文详解单例模式与工厂模式的核心实现及应用,涵盖饿汉式、懒汉式、双重检查锁、工厂方法、抽象工厂等设计模式,并结合数据库连接池与支付系统实战案例,助你掌握设计模式精髓,提升代码专业性与可维护性。
|
10月前
|
设计模式 算法 搜索推荐
Java 设计模式之策略模式:灵活切换算法的艺术
策略模式通过封装不同算法并实现灵活切换,将算法与使用解耦。以支付为例,微信、支付宝等支付方式作为独立策略,购物车根据选择调用对应支付逻辑,提升代码可维护性与扩展性,避免冗长条件判断,符合开闭原则。
2660 35
|
设计模式 网络协议 Java
04.里式替换原则介绍
里式替换原则(LSP)是面向对象设计的重要原则之一,确保子类可以无缝替换父类而不破坏程序功能。本文详细介绍了LSP的定义、背景、理解方法及应用场景,通过电商支付和鸟类飞行案例展示了如何遵循LSP,并分析了其优缺点。LSP强调子类应保持父类的行为一致性,有助于提高代码的可扩展性、可维护性和可重用性,但也可能导致过度设计。最后,对比了LSP与多态的区别,明确了LSP作为设计原则的重要性。
625 4
|
存储 关系型数据库 MySQL
MySQL 为什么使用 B+ 树作为索引结构?
MySQL 为什么使用 B+ 树作为索引结构?
657 2
|
XML JSON Java
Java 反射:从原理到实战的全面解析与应用指南
本文深度解析Java反射机制,从原理到实战应用全覆盖。首先讲解反射的概念与核心原理,包括类加载过程和`Class`对象的作用;接着详细分析反射的核心API用法,如`Class`、`Constructor`、`Method`和`Field`的操作方法;最后通过动态代理和注解驱动配置解析等实战场景,帮助读者掌握反射技术的实际应用。内容翔实,适合希望深入理解Java反射机制的开发者。
1065 13
|
XML 设计模式 Java
这6种 Spring 依赖注入方式,你都会吗?
这6种 Spring 依赖注入方式,你都会吗?
2495 1
这6种 Spring 依赖注入方式,你都会吗?
|
10月前
|
设计模式 存储 算法
Java 设计模式之迭代器模式:优雅遍历集合元素
迭代器模式将集合遍历逻辑分离为独立迭代器,实现遍历与存储解耦。支持统一接口遍历不同集合,隐藏内部结构,符合单一职责原则,广泛应用于Java集合框架。
630 159
|
开发者 人工智能 自然语言处理
欢迎使用通义灵码
灵码使用指南!一键收藏。
146961 31