当前位置: 首页 > news >正文

【HeadFirst系列之HeadFirst设计模式】第5天之工厂模式:比萨店的秘密武器,轻松搞定对象创建!

工厂模式:比萨店的秘密武器,轻松搞定对象创建!

大家好,今天我们来聊聊设计模式中的工厂模式。如果你曾经为对象的创建感到头疼,或者觉得代码中到处都是 new 关键字,那么工厂模式就是你的救星!本文基于《Head First 设计模式》的工厂模式章节,带你从比萨店的故事中轻松掌握工厂模式的精髓,附上 Java 代码示例,让你彻底理解并爱上它!
在这里插入图片描述


1. 简单工厂模式:比萨店的起步

故事背景

小明开了一家比萨店,刚开始只有两种比萨:芝士比萨素食比萨。每次接到订单,小明都会根据客户的需求,手动创建对应的比萨对象。

问题出现

随着生意越来越好,比萨的种类也越来越多。小明发现,每次新增一种比萨,都需要修改订单处理的代码。这不仅麻烦,还容易出错。

解决方案:简单工厂模式

小明决定引入简单工厂模式,将比萨的创建逻辑集中到一个工厂类中。这样,无论比萨种类如何变化,订单处理的代码都不需要修改。

代码实现

// 比萨接口
interface Pizza {void prepare();void bake();
}// 具体比萨:芝士比萨
class CheesePizza implements Pizza {@Overridepublic void prepare() {System.out.println("Preparing Cheese Pizza");}@Overridepublic void bake() {System.out.println("Baking Cheese Pizza");}
}// 具体比萨:素食比萨
class VeggiePizza implements Pizza {@Overridepublic void prepare() {System.out.println("Preparing Veggie Pizza");}@Overridepublic void bake() {System.out.println("Baking Veggie Pizza");}
}// 简单工厂
class SimplePizzaFactory {public Pizza createPizza(String pizzaType) {if (pizzaType.equals("cheese")) {return new CheesePizza();} else if (pizzaType.equals("veggie")) {return new VeggiePizza();} else {throw new IllegalArgumentException("Unknown pizza type");}}
}// 客户端代码
public class PizzaStore {public static void main(String[] args) {SimplePizzaFactory factory = new SimplePizzaFactory();Pizza pizza = factory.createPizza("cheese");pizza.prepare(); // 输出: Preparing Cheese Pizzapizza.bake();    // 输出: Baking Cheese Pizza}
}

优点

  • 将对象的创建逻辑集中在一个类中,便于维护。
  • 客户端与具体产品解耦。

缺点

  • 违反“开闭原则”,新增产品时需要修改工厂类。

2. 工厂方法模式:扩展比萨帝国

故事背景

小明的比萨店越做越大,他决定开分店!每个分店都有自己的特色比萨,比如纽约风味芝士比萨芝加哥风味素食比萨

问题出现

如果继续使用简单工厂模式,每次新增分店都需要修改工厂类,这显然不够灵活。

解决方案:工厂方法模式

小明决定采用工厂方法模式,将比萨的创建延迟到子类。每个分店都可以实现自己的比萨创建逻辑。

代码实现

// 比萨接口
interface Pizza {void prepare();void bake();
}// 具体比萨:纽约风味芝士比萨
class NYCheesePizza implements Pizza {@Overridepublic void prepare() {System.out.println("Preparing NY Style Cheese Pizza");}@Overridepublic void bake() {System.out.println("Baking NY Style Cheese Pizza");}
}// 具体比萨:芝加哥风味素食比萨
class ChicagoVeggiePizza implements Pizza {@Overridepublic void prepare() {System.out.println("Preparing Chicago Style Veggie Pizza");}@Overridepublic void bake() {System.out.println("Baking Chicago Style Veggie Pizza");}
}// 工厂接口
abstract class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza = createPizza(type);pizza.prepare();pizza.bake();return pizza;}// 工厂方法protected abstract Pizza createPizza(String type);
}// 具体工厂:纽约比萨店
class NYPizzaStore extends PizzaStore {@Overrideprotected Pizza createPizza(String type) {if (type.equals("cheese")) {return new NYCheesePizza();} else {throw new IllegalArgumentException("Unknown pizza type");}}
}// 具体工厂:芝加哥比萨店
class ChicagoPizzaStore extends PizzaStore {@Overrideprotected Pizza createPizza(String type) {if (type.equals("veggie")) {return new ChicagoVeggiePizza();} else {throw new IllegalArgumentException("Unknown pizza type");}}
}// 客户端代码
public class PizzaTest {public static void main(String[] args) {PizzaStore nyStore = new NYPizzaStore();Pizza pizza = nyStore.orderPizza("cheese"); // 输出: Preparing NY Style Cheese Pizza, Baking NY Style Cheese PizzaPizzaStore chicagoStore = new ChicagoPizzaStore();pizza = chicagoStore.orderPizza("veggie"); // 输出: Preparing Chicago Style Veggie Pizza, Baking Chicago Style Veggie Pizza}
}

优点

  • 符合“开闭原则”,新增产品时只需扩展子类。
  • 将对象的创建逻辑分散到子类,降低了耦合度。

缺点

  • 类的数量会增加,系统复杂度提高。

3. 抽象工厂模式:比萨与饮料的完美搭配

故事背景

小明发现,客户不仅喜欢比萨,还喜欢搭配饮料。于是,他决定推出套餐,每个套餐包含一款比萨和一款饮料。

问题出现

如果使用工厂方法模式,比萨和饮料的创建逻辑会分散在不同的工厂中,难以保证它们之间的兼容性。

解决方案:抽象工厂模式

小明决定采用抽象工厂模式,将比萨和饮料的创建逻辑集中到一个工厂中,确保每个套餐的比萨和饮料是兼容的。

代码实现

// 比萨接口
interface Pizza {void prepare();
}// 饮料接口
interface Drink {void serve();
}// 具体比萨:纽约风味芝士比萨
class NYCheesePizza implements Pizza {@Overridepublic void prepare() {System.out.println("Preparing NY Style Cheese Pizza");}
}// 具体饮料:纽约风味可乐
class NYCoke implements Drink {@Overridepublic void serve() {System.out.println("Serving NY Style Coke");}
}// 具体比萨:芝加哥风味素食比萨
class ChicagoVeggiePizza implements Pizza {@Overridepublic void prepare() {System.out.println("Preparing Chicago Style Veggie Pizza");}
}// 具体饮料:芝加哥风味雪碧
class ChicagoSprite implements Drink {@Overridepublic void serve() {System.out.println("Serving Chicago Style Sprite");}
}// 抽象工厂接口
interface MealFactory {Pizza createPizza();Drink createDrink();
}// 具体工厂:纽约风味套餐
class NYMealFactory implements MealFactory {@Overridepublic Pizza createPizza() {return new NYCheesePizza();}@Overridepublic Drink createDrink() {return new NYCoke();}
}// 具体工厂:芝加哥风味套餐
class ChicagoMealFactory implements MealFactory {@Overridepublic Pizza createPizza() {return new ChicagoVeggiePizza();}@Overridepublic Drink createDrink() {return new ChicagoSprite();}
}// 客户端代码
public class MealTest {public static void main(String[] args) {MealFactory nyFactory = new NYMealFactory();Pizza pizza = nyFactory.createPizza();Drink drink = nyFactory.createDrink();pizza.prepare(); // 输出: Preparing NY Style Cheese Pizzadrink.serve();   // 输出: Serving NY Style CokeMealFactory chicagoFactory = new ChicagoMealFactory();pizza = chicagoFactory.createPizza();drink = chicagoFactory.createDrink();pizza.prepare(); // 输出: Preparing Chicago Style Veggie Pizzadrink.serve();   // 输出: Serving Chicago Style Sprite}
}

优点

  • 可以创建一组相关的对象,保证它们之间的兼容性。
  • 符合“开闭原则”,新增产品族时只需扩展工厂类。

缺点

  • 类的数量会大幅增加,系统复杂度提高。

总结

工厂模式的核心思想是将对象的创建与使用分离,从而使得系统更加灵活和可维护。三种工厂模式各有优缺点:

  • 简单工厂模式:适合创建逻辑简单的场景,但违反“开闭原则”。
  • 工厂方法模式:通过子类实现对象的创建,符合“开闭原则”,但会增加类的数量。
  • 抽象工厂模式:适合创建一组相关对象的场景,但系统复杂度较高。

在实际开发中,应根据具体需求选择合适的工厂模式,以达到代码的高内聚、低耦合。希望本文能帮助你更好地理解工厂模式,并在项目中灵活运用!


互动话题
你在项目中用过工厂模式吗?遇到过哪些问题?欢迎在评论区分享你的经验!

相关文章:

【HeadFirst系列之HeadFirst设计模式】第5天之工厂模式:比萨店的秘密武器,轻松搞定对象创建!

工厂模式:比萨店的秘密武器,轻松搞定对象创建! 大家好,今天我们来聊聊设计模式中的工厂模式。如果你曾经为对象的创建感到头疼,或者觉得代码中到处都是 new 关键字,那么工厂模式就是你的救星!本…...

Redis如何解决热Key问题

目录 **如何解决 Redis 的热 Key(Hot Key)问题?****解决方案** **1. 使用多级缓存****方案** **2. 进行 Key 预分片(Key Sharding)****方案** **3. 使用 Redis 复制机制(主从复制或集群)****方案…...

从开发到部署:EasyRTC嵌入式视频通话SDK如何简化实时音视频通信的集成与应用

嵌入式设备和视频综合管理平台均支持B/S架构。在B/S架构下,传统的视频观看方式依赖于微软的OCX控件,然而OCX控件的使用正面临越来越多的挑战: 首先,用户需要安装浏览器插件、调整浏览器安全级别,并允许ActiveX控件弹出…...

Zookeeper(58)如何在Zookeeper中实现分布式锁?

在 Zookeeper 中实现分布式锁是一种常见的用例。Zookeeper 提供了强一致性、高可用性的分布式协调服务,使得它非常适合用来实现分布式锁。以下是详细的步骤和代码示例,展示如何在 Zookeeper 中实现分布式锁。 1. Zookeeper 分布式锁的基本原理 Zookeep…...

Mac端homebrew安装配置

拷打了一下午o3-mini-high,不如这位博主的超强帖子,10分钟结束战斗 跟随该文章即可,2025/2/19亲测可行 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客文章浏览阅读10w次,点赞258次,收藏837次。一直觉得自己写…...

Spring 接入 DeepSeek

引入依赖 <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency>2.yml配置 spring:ai:openai:api-key: sk-xxxxx // 填写自己申请的keybase-url: http…...

vscode将文件中行尾默认CRLF改为LF

安装prettier npm install --save-dev --save-exact prettier执行命令 npx prettier --write --end-of-line lf .即可将项目中的所有文件行尾序列格式改为lf *在你使用git拉取代码的时候&#xff0c;git会自动将代码当中与你当前系统不同的换行方式转化成你当前系统的换行方…...

python-leetcode 33.排序链表

题目&#xff1a; 给定链表的头结点head,请将其按升序排列&#xff0c;并返回排序后的链表 方法一&#xff1a;自顶向下归并排序 链表自顶向下归并排序的过程&#xff1a; 1.找到链表的中点&#xff0c;以中点为分界&#xff0c;将链表拆分成两个子链表。寻找链表的中点可以…...

【数据结构初阶第十二节】设计循环队列

云边有个稻草人-CSDN博客 必须有为成功付出代价的决心&#xff0c;然后想办法付出这个代价。 还有最后一道关于队列的习题&#xff0c;这题有点难&#xff0c;准备好迎接挑战吧&#xff01; 目录 1.【题目】 2.实现循环队列推荐用数组&#xff0c;Why? 3.Q1&#xff1a;如…...

基于微信小程序的民宿短租系统设计与实现(ssm论文源码调试讲解)

第4章 系统设计 4.1系统设计的目标 系统设计的目标是满足用户的需求和满足系统实现所需要的所有要求。本系统收集了信息浏览、信息删除、信息添加、信息修改、信息查询为一体[17]。改变了用户民宿短租的方式&#xff0c;提高管理员管理效率以及用户预订的效率。为用户、房主提…...

使用 Jetty 构建 HTTPS 服务入门指南

在互联网安全越来越重要的今天,使用 HTTPS 为 Web 服务提供安全传输成为标准配置。Jetty 是一个高性能、易用且功能丰富的开源 Java HTTP 服务器和 Servlet 容器,能够轻松实现 HTTPS 支持。本文将结合代码实例,引导您快速搭建一个基于 Jetty 的 HTTPS 服务。 一、Jetty 简介…...

数据结构《图》

数据结构《图论》 图的性质 一、无向图&#xff08;Undirected Graph&#xff09; 定义 由一组顶点&#xff08;Vertex&#xff09;和一组无向边&#xff08;Edge&#xff09;构成。 每条无向边用一条无方向的线段连接两个顶点&#xff0c;记为 ( (u, v) )&#xff0c;其中…...

用Chrome Recorder轻松完成自动化测试脚本录制

前言 入门自动化测试,录制回放通常是小白测试首先用到的功能。而录制回放工具也一直是各大Web自动化测试必然会着重提供的一块功能。 早期WinRunner、QTP这样的工具,自动化测试可以说是围绕录制回放开展的。近年像Selenium也提供有录制工具 Selenium IDE,Playwright也包含…...

⭐️苹果电脑安装windows10双系统【详细图文步骤保姆级教程】【本教材适用于MAC台式机、笔记本MacBook air和pro】

苹果电脑安装windows10双系统【详细图文步骤保姆级教程】【本教材适用于MAC台式机、笔记本MacBook air和pro】 苹果电脑安装windows10双系统一、准备工作准备项1&#xff1a;U盘作为系统安装盘准备项2&#xff1a;您需要安装的系统镜像 二、启动转换助理步骤1&#xff1a;找到启…...

win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统

目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统&#xff0c;报错&#xff1a;Operating System not found 二、原因分析 国产系统&#xff0c;需要注意的点&#xff1a; 需要看你的系统类…...

Java 大视界 -- 开源社区对 Java 大数据发展的推动与贡献(91)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

深入浅出C语言内存模型——高阶篇

在C语言编程的征途上&#xff0c;内存管理无疑是最具挑战性的部分之一。今天&#xff0c;我们将深入探讨C语言的内存模型&#xff0c;剖析其高级特性&#xff0c;并通过一系列案例&#xff0c;助你成为内存管理的佼佼者。本文为高阶篇&#xff0c;适合已经有一定C语言基础的读者…...

AI 百炼成神:逻辑回归, 垃圾邮件分类

第二个项目:逻辑回归垃圾邮件分类 项目代码下载地址:https://download.csdn.net/download/m0_56366541/90398247 项目目标 学习逻辑回归的基本概念。使用逻辑回归算法来实现垃圾邮件的分类。理解如何处理文本数据以及如何评估分类模型的性能。项目步骤 准备数据集 我们将使…...

MybatisPlus-扩展功能

逻辑删除乐观锁 MyBatisPlus从入门到精通-3&#xff08;含mp代码生成器&#xff09; Db静态工具类 Spring依赖循环问题 代码生成器 MybatisPlus代码生成器 枚举处理器 我们这里用int来存储状态 需要注解&#xff0c;很不灵活 希望用枚举类来代替这个Integer 这样的话我…...

《计算机视觉》——角点检测和特征提取sift

角点检测 角点的定义&#xff1a; 从直观上理解&#xff0c;角点是图像中两条或多条边缘的交点&#xff0c;在图像中表现为局部区域内的灰度变化较为剧烈的点。在数学和计算机视觉中&#xff0c;角点可以被定义为在两个或多个方向上具有显著变化的点。比如在一幅建筑物的图像…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...