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

跟着GPT学设计模式之工厂模式

工厂模式(Factory Design Pattern)分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。在这三种细分的工厂模式中,简单工厂、工厂方法原理比较简单,在实际的项目中也比较常用。而抽象工厂的原理稍微复杂点,在实际的项目中相对也不常用。

工厂模式是一种常见的创建型设计模式,其主要目的是封装对象的创建过程,并隐藏具体实现细节。每种方式都有其独特的优点和缺点。

下面是工厂模式的一些优点:

  • 封装对象的创建:工厂模式将对象的创建过程封装在工厂类中,客户端只需要知道如何使用工厂类来获取所需对象,而无需关心对象创建的复杂逻辑。
  • 解耦合:工厂模式可以将具体产品类与客户端代码分离,客户端只与工厂接口进行交互,通过工厂接口获取具体产品,从而降低了客户端与具体产品之间的耦合度。
  • 可扩展性:当需要新增一种具体产品时,只需要添加相应的具体产品类和相应的工厂类,而不需要修改已经存在的代码,符合开闭原则。
  • 隐藏实现细节:工厂模式可以将具体产品类的实例化过程隐藏起来,对客户端来说,只需要了解工厂接口和产品接口的定义即可,无需了解具体产品的实现细节。

缺点:

  • 类的数量增加:引入工厂模式会增加代码中的类的数量,特别是在复杂系统中,可能会引入大量的工厂类,增加了系统的复杂度。
  • 不易理解:工厂模式的实现通常需要理解多个接口和类之间的关系,对于初学者或不熟悉该模式的开发人员来说,可能会增加理解难度。
  • 开发成本增加:引入工厂模式可以提高代码的灵活性和可扩展性,但同时也带来了一定的开发成本,需要额外编写工厂类和产品类。

选择是否使用工厂模式的标准:

  • 封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
  • 代码复用:创建代码抽离到独立的工厂类之后可以复用。
  • 隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。
  • 控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。

工厂模式的实现

简单工厂

说明

简单工厂模式(Simple Factory Pattern)通过一个工厂类来封装对象的创建过程,根据不同的参数返回对应的具体产品实例。

简单工厂模式包含以下角色:

  • 工厂(Factory):负责创建具体产品的工厂类,根据传入的参数来决定创建哪种具体产品。
  • 抽象产品(Product):定义了具体产品的公共接口,所有具体产品都必须实现该接口。
  • 具体产品(Concrete Product):实现抽象产品接口的具体产品类,由工厂类根据需要创建。

简单工厂模式的步骤如下:

  • 定义抽象产品接口(或抽象类),其中描述了产品的共同特征和行为。
  • 创建具体产品类,实现抽象产品接口。
  • 创建工厂类,提供一个静态方法或实例方法,根据传入的参数动态创建并返回具体产品实例。

优点:

  • 封装了对象的创建过程,客户端只需要知道工厂类和抽象产品类即可,无需关心具体产品的创建细节。
  • 解耦合,降低了客户端与具体产品类之间的依赖关系。
  • 可以集中管理对象的创建过程,有利于后续的扩展和维护。

缺点:

  • 当新增具体产品时,需要修改工厂类的代码,违反了开闭原则。
  • 工厂类的职责相对较重,包括对象的创建和判断逻辑,随着具体产品的增多,工厂类的代码会变得臃肿。

总的来说,简单工厂模式适用于创建的产品种类较少且不会经常变动的情况。如果产品种类较多或经常变动,建议使用工厂方法模式或者抽象工厂模式。

编程示例

有一个 Car 接口,以及实现类 Ford, Ferrari。

public interface Car {String getDescription();
}public class Ford implements Car {static final String DESCRIPTION = "This is Ford.";@Overridepublic String getDescription() {return DESCRIPTION;}
}public class Ferrari implements Car {static final String DESCRIPTION = "This is Ferrari.";@Overridepublic String getDescription() {return DESCRIPTION;}
}

以下的枚举用于表示支持的 Car 类型(Ford 和 Ferrari)

public enum CarType {FORD(Ford::new), FERRARI(Ferrari::new);private final Supplier<Car> constructor; CarType(Supplier<Car> constructor) {this.constructor = constructor;}public Supplier<Car> getConstructor() {return this.constructor;}
}

接着我们实现了一个静态方法 getCar 用于封装工厂类 CarsFactory 创建 Car 具体对象实例的细节。

public class CarsFactory {public static Car getCar(CarType type) {return type.getConstructor().get();}
}

现在我们可以在客户端代码中通过工厂类创建不同类型的 Car 对象实例。

var car1 = CarsFactory.getCar(CarType.FORD);
var car2 = CarsFactory.getCar(CarType.FERRARI);
LOGGER.info(car1.getDescription());
LOGGER.info(car2.getDescription());

程序输出:

This is Ford.
This is Ferrari.

工厂方法

说明

工厂方法模式(Factory Method Pattern)将对象的创建延迟到子类中进行。工厂方法模式通过定义一个创建对象的接口,但将具体的对象创建交给子类来实现。

工厂方法模式包含以下角色:

  • 抽象产品(Product):定义了具体产品的公共接口,所有具体产品都必须实现该接口。
  • 具体产品(Concrete Product):实现抽象产品接口的具体产品类。
  • 抽象工厂(Factory):定义了创建产品对象的接口,包含一个抽象的工厂方法,由子类来实现具体的产品创建。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建具体产品的实例。

工厂方法模式的步骤如下:

  • 定义抽象产品接口(或抽象类),其中描述了产品的共同特征和行为。
  • 创建具体产品类,实现抽象产品接口。
  • 定义抽象工厂接口,声明一个工厂方法用于创建产品对象。
  • 创建具体工厂类,实现抽象工厂接口,实现工厂方法,根据需要创建并返回具体产品实例。

优点:

  • 遵循开闭原则,新增具体产品时只需创建对应的具体工厂类,无须修改抽象工厂和其他已有类的代码。
  • 通过将对象创建的责任委托给子类,解耦了客户端与具体产品的依赖关系,客户端只需要依赖于抽象工厂和抽象产品。
  • 可以轻松扩展和增加新的产品族,每个产品族对应一个具体工厂类。

缺点:

  • 每新增一个具体产品类,就需要创建一个相应的具体工厂类,导致类的个数增多,增加了系统的复杂性。
  • 客户端在使用时需要了解和依赖具体工厂类,增加了客户端代码的复杂性。

工厂方法模式适用于需要创建多个具有共同接口或基类的产品对象的情况,且这些产品对象的创建逻辑相似但可能会有差异。它提供了一种灵活的扩展机制,能够方便地添加新的产品类型,而不影响已有的代码。

编程示例

例子: 铁匠生产武器。精灵需要精灵武器,而兽人需要兽人武器。根据客户来召唤正确类型的铁匠。

public interface Blacksmith {Weapon manufactureWeapon(WeaponType weaponType);
}public class ElfBlacksmith implements Blacksmith {public Weapon manufactureWeapon(WeaponType weaponType) {return ELFARSENAL.get(weaponType);}
}public class OrcBlacksmith implements Blacksmith {public Weapon manufactureWeapon(WeaponType weaponType) {return ORCARSENAL.get(weaponType);}
}

使用工厂方法:

/*** 抽象工厂 Blacksmith 具体工厂 OrcBlacksmith  ElfBlacksmith*/
Blacksmith blacksmith = new OrcBlacksmith();
Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
LOGGER.info("{} manufactured {}", blacksmith, weapon);
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
LOGGER.info("{} manufactured {}", blacksmith, weapon);blacksmith = new ElfBlacksmith();
weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
LOGGER.info("{} manufactured {}", blacksmith, weapon);
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
LOGGER.info("{} manufactured {}", blacksmith, weapon);

程序输出:

The orc blacksmith manufactured an orcish spear
The orc blacksmith manufactured an orcish axe
The elf blacksmith manufactured an elven spear
The elf blacksmith manufactured an elven axe

抽象工厂(Abstract Factory)

通俗的讲就是工厂的工厂, 一个将单个但相关/从属的工厂分组在一起而没有指定其具体类别的工厂。

在抽象工厂模式中,有一个抽象工厂接口,定义了一系列用于创建产品对象的方法。每个具体的工厂类都实现了这个抽象工厂接口,并负责创建一组相关的产品。这些产品通常属于同一族或遵循某种主题。

关键要素:

  • 抽象工厂(Abstract Factory):定义了一组用于创建产品的方法。
  • 具体工厂(Concrete Factory):实现了抽象工厂的方法,负责创建一组相关的产品。
  • 抽象产品(Abstract Product):定义了产品的共同接口。
  • 具体产品(Concrete Product):实现了抽象产品的接口,由具体工厂创建。

优点:

  • 将产品的创建与使用相分离,客户端只需使用抽象工厂接口,无需关注具体的产品创建过程。
  • 更易于扩展和替换产品族,只需要添加新的具体工厂和具体产品即可。
编程示例

以下是抽象工厂模式的简单示例,其中AbstractFactory为抽象工厂:

// 抽象产品A
interface AbstractProductA {void operationA();
}// 具体产品A1
class ConcreteProductA1 implements AbstractProductA {public void operationA() {System.out.println("ConcreteProductA1 operationA");}
}// 具体产品A2
class ConcreteProductA2 implements AbstractProductA {public void operationA() {System.out.println("ConcreteProductA2 operationA");}
}// 抽象产品B
interface AbstractProductB {void operationB();
}// 具体产品B1
class ConcreteProductB1 implements AbstractProductB {public void operationB() {System.out.println("ConcreteProductB1 operationB");}
}// 具体产品B2
class ConcreteProductB2 implements AbstractProductB {public void operationB() {System.out.println("ConcreteProductB2 operationB");}
}// 抽象工厂
interface AbstractFactory {// 减少简单工厂的数量AbstractProductA createProductA();AbstractProductB createProductB();
}// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA1();}public AbstractProductB createProductB() {return new ConcreteProductB1();}
}// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA2();}public AbstractProductB createProductB() {return new ConcreteProductB2();}
}// 使用抽象工厂创建产品
public class Client {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();AbstractProductA productA1 = factory1.createProductA();AbstractProductB productB1 = factory1.createProductB();productA1.operationA();productB1.operationB();AbstractFactory factory2 = new ConcreteFactory2();AbstractProductA productA2 = factory2.createProductA();AbstractProductB productB2 = factory2.createProductB();productA2.operationA();productB2.operationB();}
}

输出

ConcreteProductA1 operationA
ConcreteProductB1 operationB
ConcreteProductA2 operationA
ConcreteProductB2 operationB

以上内容基于GPT创建和整理。

参考

  • 设计模式Java实现
  • 设计模式之美-王争

相关文章:

跟着GPT学设计模式之工厂模式

工厂模式&#xff08;Factory Design Pattern&#xff09;分为三种更加细分的类型&#xff1a;简单工厂、工厂方法和抽象工厂。在这三种细分的工厂模式中&#xff0c;简单工厂、工厂方法原理比较简单&#xff0c;在实际的项目中也比较常用。而抽象工厂的原理稍微复杂点&#xf…...

VScode+python开发,多个解释器切换问题

内容&#xff1a;主要VScode使用多个解释器 环境准备 VScode编辑器&#xff0c;两个版本python解释器 python3.7.2 python3.11.6 问题&#xff1a; 目前我们的电脑安装了python3.7.2、python3.11.6两个解释器&#xff0c;在vscode编辑器中&#xff0c;无法切换解释器使用如…...

c++ 经典服务器开源项目Tinywebserver如何运行

第一次直接按作者的指示&#xff0c;运行sh ./build.sh,再运行./server&#xff0c;发现不起作用&#xff0c;localhost:9006也是拒绝访问的状态&#xff0c;后来摸索成功了发现&#xff0c;运行./server之后&#xff0c;应该是启动状态&#xff0c;就是不会退出&#xff0c;而…...

c++之xml的创建,增删改查

c之xml的创建&#xff0c;增删改查 1.创建写入2.添加3.删除4.修改&#xff1a; 1.创建写入 #include <stdio.h> #include <typeinfo> #include "F:/EDGE/tinyxml/tinyxml.h" #include <iostream> #include <string> #include <Winsock2.…...

【前端开发】JS Vue React中的通用递归函数

目录 前言 一、递归函数的由来 二、功能实现 1.后台数据 2.处理数据 3.整体代码 总结 &#x1f642;博主&#xff1a;冰海恋雨. &#x1f642;文章核心&#xff1a;【前端开发】JS Vue React中的通用递归函数 前言 大家好&#xff0c;今天和大家分享一下在前端开发中j…...

【python 生成器 面试必备】yield关键字,协程必知必会系列文章--自己控制程序调度,体验做上帝的感觉 1

python生成器系列文章目录 第一章 yield — Python (Part I) 文章目录 python生成器系列文章目录前言1. Generator Function 生成器函数2.并发和并行&#xff0c;抢占式和协作式2.Let’s implement Producer/Consumer pattern using subroutine: 生成器的状态 generator’s st…...

头哥实践平台之MapReduce基础实战

一. 第1关&#xff1a;成绩统计 编程要求 使用MapReduce计算班级每个学生的最好成绩&#xff0c;输入文件路径为/user/test/input&#xff0c;请将计算后的结果输出到/user/test/output/目录下。 先写命令行,如下: 一行就是一个命令 touch file01 echo Hello World Bye Wor…...

Linux基础知识——tmux和vim

Linux基础知识——tmux和vim 文章目录 Linux基础知识——tmux和vim一、tmux1. 功能2. 结构3. 操作 二、vim功能模式操作 一、tmux tmux配置&#xff1a;~/.tmux.conf修改为如下 set-option -g status-keys vi setw -g mode-keys visetw -g monitor-activity on# setw -g c0-cha…...

Java Web——TomcatWeb服务器

目录 1. 服务器概述 1.1. 服务器硬件 1.2. 服务器软件 2. Web服务器 2.1. Tomcat服务器 2.2. 简单的Web服务器使用 1. 服务器概述 服务器指的是网络环境下为客户机提供某种服务的专用计算机&#xff0c;服务器安装有网络操作系统和各种服务器的应用系统服务器的具有高速…...

Zookeeper 命令使用和数据说明

文章目录 一、概述二、命令使用2.1 登录 ZooKeeper2.2 ls 命令&#xff0c;查看目录树&#xff08;节点&#xff09;2.3 create 命令&#xff0c;创建节点2.4 delete 命令&#xff0c;删除节点2.5 set 命令&#xff0c;设置节点数据2.6 get 命令&#xff0c;获取节点数据 三、数…...

索尼RSV文件怎么恢复为MP4视频

索尼相机RSV是什么文件&#xff1f; 如果您的相机是索尼SONY A7S3&#xff0c;A7M4&#xff0c;FX3&#xff0c;FX3&#xff0c;FX6&#xff0c;或FX9等&#xff0c;有时录像会产生一个RSV文件&#xff0c;而没有MP4视频文件。RSV其实是MP4的前期文件&#xff0c;经我对RSV文件…...

pytorch-gpu(Anaconda3+cuda+cudnn)

文章目录 下载Anaconda3安装&#xff0c;看着点next就行比较懒所以自动添加path测试 cuda安装的时候不能改路径如果出现报错&#xff0c;关闭杀毒软件一直下一步就好取消勾选“CUDA”中的“Visual Studio Intergration”一直下一步即可测试安装成功 cudnn解压后将这三个文件夹复…...

解析数据洁净之道:BI中数据清理对见解的深远影响

本文由葡萄城技术团队发布。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 随着数字化和信息化进程的不断发展&#xff0c;数据已经成为企业的一项不可或缺的重要资源。然而&#xff0c;这…...

efcore反向共工程,单元测试

1.安装efcore需要的nuget <PackageReference Include"Microsoft.EntityFrameworkCore" Version"6.0.24" /> <PackageReference Include"Microsoft.EntityFrameworkCore.SqlServer" Version"6.0.24" /> <PackageRefere…...

利用IP风险画像强化金融行业网络安全防御

在数字化时代&#xff0c;金融行业日益依赖互联网和技术创新&#xff0c;但这也使得金融机构成为网络攻击的主要目标。为了应对日益复杂的网络威胁&#xff0c;金融机构迫切需要采用先进的安全技术和工具。其中&#xff0c;IP风险画像技术成为提升网络安全的一项重要策略。 1.…...

1334. 阈值距离内邻居最少的城市

分析题目两点“阈值距离”、“邻居最少”。 “阈值距离”相当于定了个上界&#xff0c;求节点之间的最短距离。 “邻居最少”相当于能连接的点的数量。 求节点之间的最短距离有以下几种方法&#xff1a; 在这道题当中&#xff0c;n的范围是100以内&#xff0c;所以可以考虑O(n…...

Live800:客服行业的发展历程及未来前景

随着信息技术和互联网的高速发展&#xff0c;客服行业也在不断变革和发展。客服行业是一个服务型的行业&#xff0c;其发展历程也与人们对服务需求的变化密切相关。本文将介绍客服行业的发展历程和未来前景。 客服行业的发展历程 20世纪70年代&#xff0c;客服行业主要以电话服…...

exsi的安装和配置

直接虚拟真实机 vcent server 管理大量的exsi SXI原生架构模式的虚拟化技术&#xff0c;是不需要宿主操作系统的&#xff0c;它自己本身就是操作系统。因此&#xff0c;装ESXI的时候就等同于装操作系统&#xff0c;直接拿iso映像(光盘)装ESXI就可以了。 VMware vCente…...

基于springboot实现校园医疗保险管理系统【项目源码】

基于springboot实现校园医疗保险管理系统演示 系统开发平台 在线校园医疗保险系统中&#xff0c;Eclipse能给用户提供更多的方便&#xff0c;其特点一是方便学习&#xff0c;方便快捷&#xff1b;二是有非常大的信息储存量&#xff0c;主要功能是用在对数据库中查询和编程。其…...

Python 如何实现组合(Composite)设计模式?什么是组合设计模式?

什么是组合&#xff08;Composite&#xff09;设计模式&#xff1f; 组合&#xff08;Composite&#xff09;设计模式是一种结构型设计模式&#xff0c;它允许客户端使用单一对象和组合对象&#xff08;对象的组合形成树形结构&#xff09;同样的方式处理。这样&#xff0c;客…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...