概述

工厂方法模式是一种常用的创建型设计模式,它通过将对象的创建过程封装在工厂类中,实现了创建与使用的分离。这种模式不仅提高了代码的复用性,还增强了系统的灵活性和可扩展性。本文将详细介绍工厂方法模式的三种形式:简单工厂模式、工厂方法模式和抽象工厂模式,并通过Java代码示例帮助你深入理解。

什么是工厂方法模式

工厂方法模式(Factory Method Pattern)由父类提供一个创建对象的方法,允许子类决定实例化对象的类型。这种模式的核心思想是解耦 - 将对象的创建过程与使用过程分离,使得代码更容易维护和扩展。

核心优势

  • 解耦创建与使用:客户端不需要知道具体产品的创建细节
  • 提高代码复用性:创建逻辑集中在工厂中,避免代码重复
  • 增强系统扩展性:新增产品类型时只需添加相应的工厂类

在这里插入图片描述

简单工厂模式

简单工厂模式是最基础的工厂模式形式,它通过一个工厂类集中处理所有产品的创建逻辑。

实现原理

简单工厂通过一个静态方法根据传入的参数决定创建哪种产品对象。以下是基于动物示例的实现:

// 动物接口
public interface Animal {void eat();
}// 具体实现类 - 猫
public class Cat implements Animal {@Overridepublic void eat() {System.out.println("小猫吃鱼");}
}// 具体实现类 - 狗
public class Dog implements Animal {@Overridepublic void eat() {System.out.println("小狗吃骨头");}
}// 具体实现类 - 猪
public class Pig implements Animal {@Overridepublic void eat() {System.out.println("小猪吃饲料");}
}// 简单工厂类 - 由YA33提供
public class SimpleAnimalFactory {/*** 根据动物名称创建对应的动物对象* @param animalName 动物名称(cat/dog/pig)* @return 对应的动物对象,如果名称不匹配则返回null*/public static Animal createAnimal(String animalName) {if ("cat".equalsIgnoreCase(animalName)) {return new Cat();} else if ("dog".equalsIgnoreCase(animalName)) {return new Dog();} else if ("pig".equalsIgnoreCase(animalName)) {return new Pig();}return null;}
}

使用示例

// 测试类
public class SimpleFactoryTest {public static void main(String[] args) {// 通过工厂创建动物对象Animal cat = SimpleAnimalFactory.createAnimal("cat");if (cat != null) {cat.eat(); // 输出: 小猫吃鱼} else {System.out.println("无法创建指定的动物");}// 尝试创建不存在的动物Animal unknown = SimpleAnimalFactory.createAnimal("bird");if (unknown == null) {System.out.println("未知动物类型"); // 输出: 未知动物类型}}
}

优缺点分析

优点

  • 逻辑简单,易于理解
  • 将创建逻辑封装,实现创建与使用的解耦

缺点

  • 不符合开闭原则(对扩展开放,对修改关闭)
  • 新增产品类型时需要修改工厂类代码
  • 工厂类职责过重,随着产品增多会变得臃肿

工厂方法模式

为了解决简单工厂模式的问题,工厂方法模式将产品的创建延迟到子类中,让子类决定实例化哪种产品。

实现原理

工厂方法模式定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。

// 抽象工厂接口
public interface AnimalFactory {Animal createAnimal();
}// 具体工厂 - 猫工厂
public class CatFactory implements AnimalFactory {@Overridepublic Animal createAnimal() {System.out.println("创建一只小猫");return new Cat();}
}// 具体工厂 - 狗工厂
public class DogFactory implements AnimalFactory {@Overridepublic Animal createAnimal() {System.out.println("创建一只小狗");return new Dog();}
}// 具体工厂 - 猪工厂
public class PigFactory implements AnimalFactory {@Overridepublic Animal createAnimal() {System.out.println("创建一只小猪");return new Pig();}
}

使用示例

// 测试类
public class FactoryMethodTest {public static void main(String[] args) {// 使用狗工厂创建狗AnimalFactory dogFactory = new DogFactory();Animal dog = dogFactory.createAnimal();dog.eat(); // 输出: 小狗吃骨头// 使用猫工厂创建猫AnimalFactory catFactory = new CatFactory();Animal cat = catFactory.createAnimal();cat.eat(); // 输出: 小猫吃鱼}
}

优缺点分析

优点

  • 符合开闭原则,扩展性好
  • 符合单一职责原则,每个工厂只负责一种产品
  • 客户端不需要知道具体产品类名,只需要知道对应的工厂

缺点

  • 类的数量容易过多,增加系统复杂度
  • 增加了系统的抽象性和理解难度
  • 只能生产一种类型的产品(同一等级结构)

抽象工厂模式

抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

在这里插入图片描述

实现原理

抽象工厂模式包含多个工厂方法,每个工厂方法用于创建一个不同种类的对象。这些对象通常属于同一个产品族。

// 狗的子类型接口
public interface Dog extends Animal {void bark();
}// 具体狗类型 - 中华田园犬
public class RuralDog implements Dog {@Overridepublic void eat() {System.out.println("中华田园犬吃剩饭");}@Overridepublic void bark() {System.out.println("中华田园犬: 汪汪!");}
}// 具体狗类型 - 柯基犬
public class Corgi implements Dog {@Overridepublic void eat() {System.out.println("柯基犬吃狗粮");}@Overridepublic void bark() {System.out.println("柯基犬: 嗷呜!");}
}// 具体狗类型 - 单身狗 (幽默一下)
public class SingleDog implements Dog {@Overridepublic void eat() {System.out.println("单身狗吃狗粮(和自己做的饭)");}@Overridepublic void bark() {System.out.println("单身狗: 呜呜...");}
}// 抽象工厂接口 - 由YA33设计
public interface DogFactory {Dog createRuralDog();Dog createCorgi();Dog createSingleDog();
}// 具体狗工厂
public class ConcreteDogFactory implements DogFactory {@Overridepublic Dog createRuralDog() {System.out.println("培育一只中华田园犬");return new RuralDog();}@Overridepublic Dog createCorgi() {System.out.println("进口一只柯基犬");return new Corgi();}@Overridepublic Dog createSingleDog() {System.out.println("发现一只单身狗");return new SingleDog();}
}

使用示例

// 测试类
public class AbstractFactoryTest {public static void main(String[] args) {DogFactory factory = new ConcreteDogFactory();// 创建不同类型的狗Dog ruralDog = factory.createRuralDog();ruralDog.eat();ruralDog.bark();Dog corgi = factory.createCorgi();corgi.eat();corgi.bark();Dog singleDog = factory.createSingleDog();singleDog.eat();singleDog.bark();}
}

抽象工厂模式 vs 工厂方法模式

特性工厂方法模式抽象工厂模式
产品等级单一产品等级多个产品等级
产品族不支持产品族支持产品族
扩展性容易扩展新产品难以扩展新产品族
复杂度相对简单相对复杂
适用场景单一类型产品相关产品家族

模式选择指南

在实际开发中,应根据具体需求选择合适的工厂模式:

  1. 简单工厂模式:适用于产品类型较少且不经常变化的场景
  2. 工厂方法模式:适用于产品类型可能扩展,但产品族单一的場景
  3. 抽象工厂模式:适用于需要创建多个相关产品族的场景

总结

工厂方法模式及其变体为我们提供了灵活的对象创建机制。通过将对象的创建过程封装起来,我们实现了创建与使用的分离,提高了代码的可维护性和扩展性。

  • 简单工厂:简单易用,但违反开闭原则
  • 工厂方法:遵循开闭原则,适合单一产品等级结构
  • 抽象工厂:处理产品族,适合相关产品系列的创建

在实际项目中,我们应该根据具体需求选择合适的模式,避免过度设计。记住,最适合的才是最好的设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98473.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98473.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/98473.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 24.04 中 nvm 安装 Node 权限问题解决

个人博客地址:Ubuntu 24.04 中 nvm 安装 Node 权限问题解决 | 一张假钞的真实世界 参考nvm的一个issue:https://github.com/nvm-sh/nvm/issues/3363 异常信息如下: $ nvm install 22 Downloading and installing node v22.19.0... Download…

Java面试-线程安全篇

一、synchronized关键字: 基本使用与作用:通过抢票代码示例,展示了synchronized作为对象锁,可避免多线程超卖或抢到同一张票问题,保证代码原子性,同一时刻只有一个线程获得锁,其他线程阻塞。底层…

R 语言科研绘图 --- 其他绘图-汇总2

在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…

【数学建模学习笔记】启发式算法:粒子群算法

零基础小白看懂粒子群优化算法(PSO)一、什么是粒子群优化算法?简单说,粒子群优化算法(PSO)是一种模拟鸟群 / 鱼群觅食的智能算法。想象一群鸟在找食物:每只鸟(叫 “粒子”&#xff0…

【Gitlab】Ubuntu 20.04服务器部署Gitlab

写一个 适用于 Ubuntu 20.04/22.04 的 GitLab 一键部署脚本,包括:安装依赖安装 GitLab CE配置公网 IP 或域名自动开启 HTTPS(Let’s Encrypt)配置防火墙下面是完整脚本:#!/bin/bash# # GitLab 一键安装脚本 # # 1. 检…

Android 15重磅升级:16KB内存页机制详解与适配指南

一、背景随着Android硬件架构的持续演进,新一代设备开始采用16KB内存页(Page Size)机制,逐步替代传统的4KB内存页设计。此项底层变更对应用兼容性产生直接影响,特别是对依赖Native层库、JNI接口或自定义内存管理模块的…

Mybatis-8 动态SQL

动态SQL-官方文档 文档地址 动态 SQL_MyBatis中文网 为什么需要动态SQL 1、动态SQL是MyBatis的强大特性之一 2、使用JDBC或其它类似的框架,根据不同条件拼接SQL语句非常麻烦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一…

PySpark数据输入

PySpark数据输入 1.理解RDD对象 2.掌握PySpark数据输入的2种方法 RDD对象 PySpark支持多种数据的输入,在输入完成后,都会得到一个:RDD类的对象 RDD全称为:弹性分布式数据集(Resilient Distributed Datasets&#xff09…

【系统架构设计(16)】软件架构设计二:软件架构风格:构建系统的设计模式与选择指南

文章目录一、核心思想二、数据流风格:以数据流动为核心的处理模式三、调用返回风格:基于程序调用的层次化组织四、独立构件风格:基于事件驱动的松耦合架构五、虚拟机风格:提供抽象执行环境的架构模式六、仓库风格:以数…

MySQL速记小册(1)

1【Q】:Mysql中的数据排序是怎么实现的?【A】:排序过程中如果字段有索引,则利用索引排序。反之使用文件排序。在文件排序中,如果数据量少则在内存中排序,使用单路排序或双路排序。如果数据量大则利于磁盘文…

20250904 10:45_排查10.1.3.35新QMS系统RMAN备份失败问题(优化脚本里的环境配置,增加了check_oracle_env 函数)

一、RMAN备份失败日志如下 [2025-09-04 04:00:01] 备份脚本启动 [2025-09-04 04:00:01] 开始 RMAN 备份 CDB: ORCLCDB Message file RMAN<lang>.msb not found Verify that ORACLE_HOME is set properly [2025-09-04 04:00:01] RMAN 备份失败! 二、原备份脚本存档…

Vue3源码reactivity响应式篇之EffectScope

概述 EffectScope是Vue3中一个响应式系统的辅助类&#xff0c;用于管理副作用&#xff08;effect&#xff09;的作用域。它可以帮助我们更好地组织和管理多个effect&#xff0c;便于一起停止或暂停以及恢复&#xff0c;避免了全局状态的污染和管理的复杂性。 每一个vue组件的实…

MySQL 日志全解析:Binlog/Redo/Undo 等 5 类关键日志的配置、作用与最佳实践

1 二进制日志&#xff08;Binlog&#xff09;&#xff1a;配置与核心作用 Binlog 是 MySQL 中跨存储引擎的核心日志&#xff0c;记录所有数据修改操作&#xff0c;主要用于主从复制、数据备份恢复与跨库迁移。 1.1 Binlog 核心操作 开启 Binlog 若需开启 Binlog&#xff0c;需在…

springboot 之 HTML与图片生成 (2)

前言 之前写了一篇html转图片的 文章&#xff0c;使用中文时会出现乱码情况&#xff0c;后来又从网上找了下信息&#xff0c;这篇主要介绍下另一个转换库。 依赖 <!-- 用于将html转图片--><dependency><groupId>gui.ava</groupId><artifactId>…

计算机组成原理:计算机的分类

&#x1f4cc;目录&#x1f5a5;️ 计算机组成原理&#xff1a;计算机的分类——从架构到应用的全景梳理一、按处理数据类型分类&#xff1a;从“数字”到“混合”的演进&#xff08;一&#xff09;数字计算机&#xff1a;离散数据的“精准管家”1. 核心原理2. 关键优势3. 典型…

数据结构——单向循环链表代码(补充)

在此前的文章中&#xff08;链接如下&#xff09;&#xff0c;只有单向链表的代码&#xff0c;接下来我们来写单向循环链表&#xff0c;并用其实现一个简单的学生信息链表https://blog.csdn.net/2301_80406299/article/details/151157051?spm1011.2415.3001.10575&sharefr…

【Python自动化】 21.2 Pandas 读取 Excel 时的 dtype 参数完全指南

一、dtype 参数概述 dtype 参数用于指定列的数据类型&#xff0c;在读取 Excel 时非常重要&#xff0c;可以&#xff1a; 提高内存效率避免自动类型推断错误确保数据一致性提升读取性能 二、基本用法 1. 基础语法 import pandas as pd# 指定列数据类型 df pd.read_excel(data.…

gtest全局套件的测试使用

gtest全局套件的测试使用 #include <iostream> #include "gtest/gtest.h" #include <unordered_map>class MyEnvironment: public testing::Environment {public:virtual void SetUp() override{std::cout<<"单元测试前的环境初始化&#xff…

【系统分析师】第7章-基础知识:软件工程(核心总结)

更多内容请见: 备考系统分析师-专栏介绍和目录 文章目录 一、软件工程的基本概念 1.1 定义与意义 1.2 软件工程的基本原则 1.3 核心定义与边界 1.4 四大核心原则 1.5 三大核心目标 二、软件生命周期 2.1 定义与阶段划分 2.2 软件生命周期模型 三、软件开发方法 3.1 结构化方法…

量化基金从小白到大师 - 金融数据获取大全:从免费API到Tick级数据实战指南

量化基金从小白到大师 - 金融数据获取大全&#xff1a;从免费API到Tick级数据实战指南 各位&#xff0c;今天咱们要啃一块硬骨头——金融数据获取。别看这话题基础&#xff0c;它可是整个量化大厦的地基&#xff0c;地基不稳&#xff0c;再牛的策略都得塌房。我见过太多人&…