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

工厂设计模式(Factory Pattern):工厂方法与抽象工厂的实例演示

工厂模式(Factory Pattern)是面向对象编程中最经典、也是最常用的创建型设计模式之一。

简单来说,工厂模式的核心思想就是:将“创建对象”的过程封装起来。对象的使用方不需要知道对象具体是如何被 new 出来的,只需要告诉“工厂”自己需要什么,工厂就会把做好的对象交给你。

之所以这么做,最主要就是解决了对象使用方和创建对象的耦合,在代码层面,客户端无需直接使用 new,对象的创建由工厂负责。否则,当需要使用到一个对象时,自己去 new,就需要考虑到创建这个对象的各种细节,例如构造参数等。

工厂模式有三种:

  1. 简单工厂模式
  2. 工厂方法模式
  3. 抽象工厂模式

首先,既然是工厂模式,那我们先把要生产的产品定义出来,以便后面演示:

// 定义产品接口interfaceProduct{voidgetName();}classXiaomiComputerimplementsProduct{@OverridepublicvoidgetName(){System.out.println("小米电脑");}}classApplePhoneimplementsProduct{@OverridepublicvoidgetName(){System.out.println("苹果手机");}}

工厂模式本质是封装对象创建,客户端只依赖抽象产品(接口或抽象类)而不依赖具体类。因此必须有一个抽象产品,工厂方法或抽象工厂才有意义,因此我们定义了Product这个接口。

另外,工厂模式是对“创建行为”的设计规范,产品接口的设计由你的业务需求决定,你只需要有个抽象产品接口用于工厂的返回。

简单工厂模式(Simple Factory)

简单工厂模式有时也叫静态工厂模式,但它并不能算是一个正式的设计模式,只是一种常用的对象创建方式(其实就是一个方法)。在简单工厂模式中,通常会有一个工厂类,它根据参数的不同返回不同类型的对象。

使用简单工厂模式甚至都不用定义工厂的接口,直接创建一个实现类即可,你其实就可以将这个简单工厂理解为一个switch方法而已:

classSimpleFactory{publicstaticProductcreateProduct(Stringtype){switch(type){case"小米电脑":returnnewXiaomiComputer();case"苹果手机":returnnewApplePhone();default:returnnull;}}}

对于产品的使用者来说,需要什么产品仅仅需要传入对应的参数即可:

classCustomer{publicstaticvoidmain(String[]args){SimpleFactory.createProduct("小米电脑").getName();SimpleFactory.createProduct("苹果手机").getName();}}

可以看出简单工厂模式的优点是简单,对于产品的创建其实就是一个switch方法,不过这显然就违背了开闭原则(对于扩展开放,对于修改关闭)。因为要添加新的产品,就需要修改这个switch方法,添加新case,这违背了开闭原则中“对修改关闭”的理念。

因此这就引出了工厂方法模式。

工厂方法模式(Factory Method)

工厂方法模式定义了一个工厂接口,对于每个产品,都会有一个工厂接口的实现类来负责创建。这样就避免了简单工厂模式的扩展问题:

// 工厂方法模式的工厂接口interfaceFactory{ProductcreateProduct();}// 小米电脑工厂classXiaomiComputerFactoryimplementsFactory{@OverridepublicProductcreateProduct(){returnnewXiaomiComputer();}}// 苹果手机工厂classApplePhoneFactoryimplementsFactory{@OverridepublicProductcreateProduct(){returnnewApplePhone();}}

当产品使用者需要用到某个产品时,需要先创建对应的工厂,然后用工厂来创建对应的产品:

classCustomer{publicstaticvoidmain(String[]args){FactoryxiaomiComputerFactory=newXiaomiComputerFactory();ProductxiaomiComputer=xiaomiComputerFactory.createProduct();xiaomiComputer.getName();FactoryapplePhoneFactory=newApplePhoneFactory();ProductapplePhone=applePhoneFactory.createProduct();applePhone.getName();}}

从代码里可见,工厂方法模式在增加新产品时无需修改现有工厂,只需要增加一个新的工厂类而已,已有工厂无需修改,符合开闭原则。 不过它也带来了一个缺点:类数量增多,每增加一种产品就需要增加一个工厂类。

这就引出了工厂模式的最终形态——可以生产“产品家族”的抽象工厂模式。

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory Pattern)是工厂模式的进一步升级,用来创建一系列相关或相互依赖的对象,而无需指定它们的具体类。

简单的说,工厂方法中,每一个工厂只能创建一个产品,而在抽象工厂中,每个工厂能创建一系列相关的产品。

为了演示抽象工厂模式,我们新增小米手机和苹果电脑产品:

classXiaomiPhoneimplementsProduct{@OverridepublicvoidgetName(){System.out.println("小米手机");}}classAppleComputerimplementsProduct{@OverridepublicvoidgetName(){System.out.println("苹果电脑");}}

由于每个工厂可以生产多个产品,因此需要更改工厂接口的定义和实现:

// 抽象工厂模式的工厂接口interfaceAbstractFactory{ProductcreatePhone();ProductcreateComputer();}classXiaomiFactoryimplementsAbstractFactory{@OverridepublicProductcreatePhone(){returnnewXiaomiPhone();}@OverridepublicProductcreateComputer(){returnnewXiaomiComputer();}}classAppleFactoryimplementsAbstractFactory{@OverridepublicProductcreatePhone(){returnnewApplePhone();}@OverridepublicProductcreateComputer(){returnnewAppleComputer();}}

这里的工厂接口AbstractFactory只返回Product类型,有些时候抽象工厂接口针对不同的产品返回不同的接口类型,不过这并不是工厂模式的要求。抽象工厂模式要求产品使用方依赖抽象,而不是具体产品类,接口设计可以根据实际业务灵活选择,不必强制拆分。可以返回统一接口,也可以返回不同的产品接口,选择哪种方式取决于业务需求和产品操作差异。

这里,产品使用方可以使用如下代码使用工厂创建需要的产品:

classCustomer{publicstaticvoidmain(String[]args){AbstractFactoryxiaomiFactory=newXiaomiFactory();ProductxiaomiPhone=xiaomiFactory.createPhone();xiaomiPhone.getName();AbstractFactoryappleFactory=newAppleFactory();ProductapplePhone=appleFactory.createPhone();applePhone.getName();}}

从以上例子可以看出抽象工厂的特点:一个工厂创建一系列产品,且增加一个新的工厂比较容易(例如这里增加一个魅族工厂),但如果产品族中新增了一个产品类型,那所有的工厂就都得修改代码了。

总结

  • 简单工厂模式:适合产品少、变化不频繁,使用方便,但违背开闭原则。
  • 工厂方法模式:适合单个产品扩展,增加新产品无需修改已有工厂,但工厂类数量会增加。
  • 抽象工厂模式:适合创建一系列相关产品,保证产品族一致性,增加产品族方便,但新增产品类型时需修改所有工厂。

选择模式时,可根据产品数量、产品族关系以及扩展需求选择最合适的方案。

http://www.jsqmd.com/news/786388/

相关文章:

  • CANN盘古7B配置说明
  • 一键提取视频PPT:开源智能视频内容自动化提取的革命性工具
  • 平滑滚动技术:从原理到实现,打造丝滑交互体验
  • ARM64缓存维护指令DC CVAC详解与应用
  • 5G R18标准:AI/ML如何重塑空口优化与网络架构
  • 终极Blender插件:快速解决虚幻引擎PSK/PSA格式转换难题
  • 3PEAK思瑞浦 TP2264-TS2R-S TSSOP14 运算放大器
  • 多模态大模型Awesome列表:从资源导航到高效学习与开发实践
  • 保姆级 Kali Linux 安装教程|零基础小白也能看懂,从镜像下载到虚拟机配置全程图文详解,零报错上手
  • py每日spider案例之某五八登录接口逆向(RSA算法 难度中等)
  • CANN Triton GE后端实现
  • CANN/opbase算子定义接口
  • Arch Linux自动化部署与深度定制:从脚本化安装到系统优化实战
  • SpiderDemo第一关
  • AArch64虚拟内存系统地址转换与参数配置详解
  • ViGEmBus驱动实战指南:从内核级模拟到性能调优的完整解决方案
  • Taotoken的用量看板让我们的月度AI支出变得清晰可预测
  • Hitboxer:如何用开源工具解决游戏按键冲突的终极方案
  • 三份假文档如何轻取AI知识库?RAG系统漏洞大揭秘!
  • STM32F103 学习笔记-21-串口通信(第5节)—串口2345代码移植和讲解
  • CANN/ops-rand API 实现状态
  • React聊天机器人组件集成指南:从UI定制到AI后端连接
  • 从特征工程到深度学习:AI视网膜疾病诊断的技术演进与工程实践
  • 脑机接口与LLM融合:EEGChat项目实现脑电信号到文本的意图解码
  • 【C++】stackqueuedequepriority_queue深度剖析
  • Codex Mac 安装报错解决教程(应用程序“Codex“无法打开)
  • 第一行代码--初步学习--UI开发--ListView
  • 自动化立体仓库系统项目施工要点
  • Win系统实现网络转发与端口映射:从 IPEnableRouter 到 RRAS 完整步骤
  • 如何快速掌握Blender插件io_scene_psk_psa:虚幻引擎PSK/PSA格式完整指南