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

零基础设计模式——创建型模式 - 抽象工厂模式

第二部分:创建型模式 - 抽象工厂模式 (Abstract Factory Pattern)

我们已经学习了单例模式(保证唯一实例)和工厂方法模式(延迟创建到子类)。现在,我们来探讨创建型模式中更为复杂和强大的一个——抽象工厂模式。它处理的是创建“产品族”的问题。

  • 核心思想:提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。

抽象工厂模式 (Abstract Factory Pattern)

“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。”

想象一下,你要装修房子,可以选择不同的装修风格,比如“现代风格”、“中式风格”或“欧式风格”。

  • 每种风格都包含一系列配套的家具:沙发、茶几、电视柜等。
  • “现代风格”的家具(现代沙发、现代茶几)是一套,它们之间风格统一。
  • “中式风格”的家具(红木沙发、雕花茶几)是另一套,它们也风格统一。

你不会用一个现代风格的沙发去搭配一个中式雕花的茶几,这样会显得不伦不类。抽象工厂模式就是用来确保你得到的是一整套风格协调的产品。

1. 目的 (Intent)

抽象工厂模式的主要目的:

  1. 创建产品族:核心在于创建一系列相关的或相互依赖的对象(称为一个“产品族”)。例如,一个UI工具包工厂可能创建按钮、文本框、滚动条等一系列UI组件,这些组件需要有统一的外观和行为(如Windows风格或macOS风格)。
  2. 客户端与具体类解耦:客户端代码只与抽象的工厂接口和抽象的产品接口打交道,而不需要知道具体是哪个工厂的实现,也不需要知道具体的产品类名。
  3. 保证产品兼容性:由同一个具体工厂创建出来的产品,一定是相互兼容、可以协同工作的。

2. 生活中的例子 (Real-world Analogy)

  • 电脑组装

    • 抽象工厂 (AbstractFactory)ComputerPartsFactory (定义了创建CPU、主板、内存等组件的接口)。
    • 具体工厂 (ConcreteFactory)IntelCompatibleFactory (生产Intel CPU、兼容主板、特定内存条),AMDCompatibleFactory (生产AMD CPU、兼容主板、另一特定内存条)。
    • 抽象产品 (AbstractProduct)CPU, Motherboard, RAM (这些是组件的抽象接口)。
    • 具体产品 (ConcreteProduct)IntelCPU, AMDRyzenCPU, AsusMotherboard, GigabyteMotherboard, KingstonRAM, CorsairRAM
      当你选择 IntelCompatibleFactory 时,你会得到一套相互兼容的Intel平台组件。你不会得到一个Intel的CPU却配一个只支持AMD的主板。
  • 换肤功能 (Skinnable UI)

    • 抽象工厂UIThemeFactory (定义 createButton(), createCheckbox(), createWindow() 等方法)。
    • 具体工厂WindowsThemeFactory (创建Windows风格的按钮、复选框、窗口),MacThemeFactory (创建Mac风格的按钮、复选框、窗口),DarkThemeFactory (创建暗黑主题的组件)。
    • 抽象产品Button, Checkbox, Window (UI组件的接口)。
    • 具体产品WindowsButton, MacButton, DarkButton 等。
      用户选择一个主题(比如“暗黑主题”),应用就会使用 DarkThemeFactory 来创建所有UI元素,确保界面风格统一。

3. 结构 (Structure)

抽象工厂模式通常包含以下角色:

  1. AbstractFactory (抽象工厂):声明一个创建抽象产品对象的操作接口集合。通常每个抽象产品对应一个创建方法。
  2. ConcreteFactory (具体工厂):实现 AbstractFactory 接口,负责创建具体产品族中的产品对象。系统可以有多个具体工厂,每个具体工厂创建一个具体的产品族。
  3. AbstractProduct (抽象产品):为一类产品对象声明一个接口。系统中可以有多个不同的抽象产品,构成产品族。
  4. ConcreteProduct (具体产品):定义一个将被相应的具体工厂创建的产品对象。它实现了 AbstractProduct 接口。
  5. Client (客户端):仅使用 AbstractFactory 和 AbstractProduct 接口。客户端不关心具体是哪个工厂、哪个产品,它只知道它需要一个工厂来创建它需要的产品。
    在这里插入图片描述

4. 适用场景 (When to Use)

  • 一个系统要独立于它的产品的创建、组合和表示时。即,你希望客户端代码与具体产品的创建过程分离。
  • 一个系统要由多个产品系列中的一个来配置时。例如,系统需要支持多种“外观感觉”(Look and Feel)。
  • 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
  • 当你提供一个产品类库,而只想显示它们的接口而不是实现时。

简单来说:

  • 需要创建的产品对象有复杂的关联关系(属于同一个产品族)
  • 系统需要支持不同系列(族)的产品,并且可以在运行时切换

5. 优缺点 (Pros and Cons)

优点:

  1. 分离接口和实现:客户端使用抽象接口,与具体的产品实现解耦。
  2. 易于交换产品系列:改变具体工厂即可改变整个产品系列,客户端代码无需修改。
  3. 有利于产品的一致性:当一个系列的产品对象被设计成一起工作时,抽象工厂模式能够保证客户端始终只使用同一个产品系列中的对象。

缺点:

  1. 难以扩展新的产品种类 (Product Kind):如果要在产品族中增加一个新的产品种类(例如,在UI主题工厂中增加创建 ScrollBar 的方法),那么所有的抽象工厂接口和具体工厂实现都需要修改,这违反了开闭原则。对于这种情况,工厂方法模式可能更合适(每个产品种类一个工厂方法)。
  2. 类的数量会显著增加:每增加一个产品族,就需要增加一套对应的具体产品类和具体工厂类。

6. 实现方式 (Implementations)

让我们通过一个跨平台UI组件的例子来看看抽象工厂模式的实现。假设我们需要为Windows和macOS创建风格一致的按钮和文本框。

抽象产品 (Button, TextBox)
// ui_elements.go
package ui// Button 按钮接口 (抽象产品A)
type Button interface {Render()OnClick()
}// TextBox 文本框接口 (抽象产品B)
type TextBox interface {Render()SetText(text string)GetText() string
}
// Button.java
package com.example.ui;// 按钮接口 (抽象产品A)
public interface Button {void render();void onClick();
}// TextBox.java
package com.example.ui;// 文本框接口 (抽象产品B)
public interface TextBox {void render();void setText(String text);String getText();
}
具体产品 (WindowsButton, WindowsTextBox, MacButton, MacTextBox)
// windows_elements.go
package uiimport "fmt"// WindowsButton Windows风格按钮 (具体产品A1)
type WindowsButton struct{}func (b *WindowsButton) Render()  { fmt.Println("Rendering a Windows style button.") }
func (b *WindowsButton) OnClick() { fmt.Println("Windows button clicked.") }// WindowsTextBox Windows风格文本框 (具体产品B1)
type WindowsTextBox struct{ text string }func (tb *WindowsTextBox) Render()        { fmt.Println("Rendering a Windows style text box.") }
func (tb *WindowsTextBox) SetText(text string) { tb.text = text }
func (tb *WindowsTextBox) GetText() string   { return tb.text }// mac_elements.go
package uiimport "fmt"// MacButton Mac风格按钮 (具体产品A2)
type MacButton struct{}func (b *MacButton) Render()  { fmt.Println("Rendering a macOS style button.") }
func (b *MacButton) OnClick() { fmt.Println("macOS button clicked.") }// MacTextBox Mac风格文本框 (具体产品B2)
type MacTextBox struct{ text string }func (tb *MacTextBox) Render()        { fmt.Println("Rendering a macOS style text box.") }
func (tb *MacTextBox) SetText(text string) { tb.text = text }
func (tb *MacTextBox) GetText() string   { return tb.text }
// WindowsButton.java
package com.example.ui.windows;import com.example.ui.Button;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;// Windows风格按钮 (具体产品A1)
public class WindowsButton implements Button {@Overridepublic void render() {System.out.println("Rendering a Windows style button.");// 实际场景中可能会使用Swing/JavaFX等创建真实UI// JFrame frame = new JFrame("Windows Button");// JButton button = new JButton("Win Button");// button.addActionListener(e -> onClick());// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// frame.setLayout(new FlowLayout());// frame.add(button);// frame.setSize(200, 100);// frame.setVisible(true);}@Overridepublic void onClick() {System.out.println("Windows button clicked.");// JOptionPane.showMessageDialog(null, "Windows Button Clicked!");}
}// WindowsTextBox.java
package com.example.ui.windows;import com.example.ui.TextBox;// Windows风格文本框 (具体产品B1)
public class WindowsTextBox implements TextBox {private String text = "";@Overridepublic void render() {System.out.println("Rendering a Windows style text box: [" + text + "]");}@Overridepublic void setText(String text) { this.text = text; }@Overridepublic String getText() { return this.text; }
}// MacButton.java
package com.example.ui.mac;import com.example.ui.Button;// Mac风格按钮 (具体产品A2)
public class MacButton implements Button {@Overridepublic void render() {System.out.println("Rendering a macOS style button.");}@Overridepublic void onClick() {System.out.println("macOS button clicked.");}
}// MacTextBox.java
package com.example.ui.mac;import com.example.ui.TextBox;// Mac风格文本框 (具体产品B2)
public class MacTextBox implements TextBox {private String text = "";@Overridepublic void render() {System.out.println("Rendering a macOS style text box: (" + text + ")");}@Overridepublic void setText(String text) { this.text = text; }@Overridepublic String getText() { return this.text; }
}
抽象工厂 (GUIFactory)
// gui_factory.go
package ui// GUIFactory 抽象UI工厂 (抽象工厂)
type GUIFactory interface {CreateButton() ButtonCreateTextBox() TextBox
}
// GUIFactory.java
package com.example.ui;// 抽象UI工厂 (抽象工厂)
public interface GUIFactory {Button createButton();TextBox createTextBox();
}
具体工厂 (WindowsFactory, MacFactory)
// windows_factory.go
package ui// WindowsFactory Windows UI工厂 (具体工厂1)
type WindowsFactory struct{}func (wf *WindowsFactory) CreateButton() Button {return &WindowsButton{}
}
func (wf *WindowsFactory) CreateTextBox() TextBox {return &WindowsTextBox{}
}// mac_factory.go
package ui// MacFactory Mac UI工厂 (具体工厂2)
type MacFactory struct{}func (mf *MacFactory) CreateButton() Button {return &MacButton{}
}
func (mf *MacFactory) CreateTextBox() TextBox {return &MacTextBox{}
}
// WindowsFactory.java
package com.example.ui.windows;import com.example.ui.Button;
import com.example.ui.GUIFactory;
import com.example.ui.TextBox;// Windows UI工厂 (具体工厂1)
public class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {System.out.println("WindowsFactory: Creating WindowsButton");return new WindowsButton();}@Overridepublic TextBox createTextBox() {System.out.println("WindowsFactory: Creating WindowsTextBox");return new WindowsTextBox();}
}// MacFactory.java
package com.example.ui.mac;import com.example.ui.Button;
import com.example.ui.GUIFactory;
import com.example.ui.TextBox;// Mac UI工厂 (具体工厂2)
public class MacFactory implements GUIFactory {@Overridepublic Button createButton() {System.out.println("MacFactory: Creating MacButton");return new MacButton();}@Overridepublic TextBox createTextBox() {System.out.println("MacFactory: Creating MacTextBox");return new MacTextBox();}
}
客户端使用 (Application)
// main.go (示例用法)
/*
package mainimport ("fmt""./ui" // 假设 ui 包在当前目录下"runtime"
)// Application 客户端,它不知道具体的工厂和产品类
type Application struct {factory GUIFactorybutton  ButtontextBox TextBox
}func NewApplication(factory ui.GUIFactory) *Application {app := &Application{factory: factory}app.button = factory.CreateButton()app.textBox = factory.CreateTextBox()return app
}func (app *Application) Run() {app.button.Render()app.button.OnClick()app.textBox.SetText("Hello Abstract Factory!")app.textBox.Render()fmt.Println("Text from box:", app.textBox.GetText())
}func main() {var factory ui.GUIFactory// 根据操作系统选择不同的工厂os := runtime.GOOSfmt.Println("Operating System:", os)if os == "windows" {factory = &ui.WindowsFactory{}} else if os == "darwin" { // darwin is macOSfactory = &ui.MacFactory{}} else {fmt.Println("Unsupported OS, defaulting to Windows style.")factory = &ui.WindowsFactory{} // 默认或提供一个通用工厂}app := NewApplication(factory)app.Run()
}
*/
// Application.java (客户端)
package com.example;import com.example.ui.Button;
import com.example.ui.GUIFactory;
import com.example.ui.TextBox;
import com.example.ui.mac.MacFactory;
import com.example.ui.windows.WindowsFactory;public class Application {private Button button;private TextBox textBox;public Application(GUIFactory factory) {System.out.println("Client: Configuring application with a UI factory.");button = factory.createButton();textBox = factory.createTextBox();}public void run() {System.out.println("\nClient: Running the application UI...");button.render();button.onClick();textBox.setText("Hello Abstract Factory!");textBox.render();System.out.println("Text from box: " + textBox.getText() + "\n");}// Main.java (示例用法)/*public static void main(String[] args) {GUIFactory factory;Application app;String osName = System.getProperty("os.name").toLowerCase();System.out.println("Operating System: " + osName);if (osName.contains("win")) {factory = new WindowsFactory();} else if (osName.contains("mac")) {factory = new MacFactory();} else {System.out.println("Unsupported OS, defaulting to Windows style.");factory = new WindowsFactory(); // Default factory}app = new Application(factory);app.run();// 假设我们现在想切换到Mac主题 (如果当前不是Mac)if (!osName.contains("mac")) {System.out.println("\n--- Switching to Mac Theme for demonstration ---");factory = new MacFactory();app = new Application(factory);app.run();}}*/
}

7. 与工厂方法模式的区别

抽象工厂模式和工厂方法模式是初学者容易混淆的两个模式。

  • 工厂方法模式 (Factory Method)

    • 关注点:创建单个产品对象
    • 结构:一个抽象工厂接口(通常只有一个创建方法 factoryMethod()),多个具体工厂实现它来创建不同的具体产品。
    • 目的:延迟产品的实例化到子类。
    • 解决问题:如何创建一个对象,但让子类决定具体创建哪个对象。
  • 抽象工厂模式 (Abstract Factory)

    • 关注点:创建一系列相关的产品对象(一个产品族)
    • 结构:一个抽象工厂接口(包含多个创建不同种类产品的抽象方法,如 createProductA(), createProductB()),多个具体工厂实现它来创建属于同一个产品族的不同具体产品。
    • 目的:提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
    • 解决问题:如何创建一组相互关联/依赖的对象,并保证它们之间是兼容的。

简单来说

  • 如果你只需要创建一种产品,但希望由子类决定具体创建哪种类型,用工厂方法
  • 如果你需要创建多种产品,这些产品需要配套使用(属于一个系列/族),并且希望客户端与具体产品解耦,用抽象工厂

实际上,抽象工厂模式的实现中,每个具体工厂内部的创建方法(如 createButton())通常可以使用工厂方法模式来实现,或者直接 new 具体产品。

8. 总结

抽象工厂模式是创建型模式中功能最强大但也相对复杂的模式之一。它通过提供一个抽象接口来创建一系列相关的产品对象(产品族),使得客户端代码可以独立于具体的产品实现。这对于需要支持多种产品系列(例如不同的UI主题、不同的数据库实现)并且希望在它们之间轻松切换的系统非常有用。

记住它的核心:创建产品家族,保证兼容性

相关文章:

零基础设计模式——创建型模式 - 抽象工厂模式

第二部分:创建型模式 - 抽象工厂模式 (Abstract Factory Pattern) 我们已经学习了单例模式(保证唯一实例)和工厂方法模式(延迟创建到子类)。现在,我们来探讨创建型模式中更为复杂和强大的一个——抽象工厂…...

解锁内心的冲突:神经症冲突的理解与解决之道

目录 一、神经症冲突概述 二、冲突的基本类型 三、未解决冲突的后果 四、尝试解决的途径 五、真正解决冲突 六、总结 干货分享,感谢您的阅读! 人类的内心世界复杂多变,常常充满了各种冲突和矛盾。每个人在成长的过程中,都或…...

JVM—Java对象

JVM中的Java对象在堆内存中的存储分布可以分为对象头,实例数据和对齐填充三部分 对象头: 包含运行时元数据和类型指针 1、Mark Word(标记字段) 对象自身的运行时数据: 锁状态标志(无锁、偏向锁、轻量级…...

Redisson读写锁和分布式锁的项目实践

解决方案:采用读写锁 什么是读写锁 Redisson读写锁是一种基于Redis实现特殊的机制,用于在分布式系统中协调对共享资源的访问,其继承了Java中的ReentrantReadWriteLock的思想.特别适用于读多写少的场景.其核心是:允许多个线程同时读取共享资源,但写操作必须占用资源.从而保证线…...

Https流式输出一次输出一大段,一卡一卡的-解决方案

【背景】 最近遇到一个奇怪的现象,前端vue,后端python,服务部署在服务器上面后,本来一切正常,但公司说要使用https访问,想着也没什么问题,切过去发现在没有更改任何代码的情况下,ht…...

SkyWalking高频采集泄漏线程导致CPU满载排查思路

SkyWalking高频采集泄漏线程导致CPU满载排查思路 契机 最近在消除线上服务告警,发现Java线上测试服经常CPU满载告警,以前都是重启解决,今天好好研究下,打arthas火焰图发现是SkyWalking-agent的线程采集任务一直在吃cpu&#xff…...

【HarmonyOS 5】Map Kit 地图服务之应用内地图加载

#HarmonyOS SDK应用服务,#Map Kit,#应用内地图 目录 前期准备 AGC 平台创建项目并创建APP ID 生成调试证书 生成应用证书 p12 与签名文件 csr 获取 cer 数字证书文件 获取 p7b 证书文件 配置项目签名 配置签名证书指纹 项目开发 配置Client I…...

ld: cpu type/subtype in slice (arm64e.old) does not match fat header (arm64e)

ld: cpu type/subtype in slice (arm64e.old) does not match fat header (arm64e) in ‘/Users/*****/MposApp/MposApp/Modules/Common/Mpos/NewLand/MESDK.framework/MESDK’ clang: error: linker command failed with exit code 1 (use -v to see invocation) 报错 解决方…...

sentinel核心原理-高频问题

核心原理 ‌限流实现机制‌ ‌滑动窗口算法‌:将时间切分为子窗口动态统计QPS,避免固定窗口的边界问题。‌责任链模式‌:通过NodeSelectorSlot、FlowSlot等Slot链式处理限流逻辑。 ‌熔断降级策略‌ ‌慢调用比例‌:当慢请求比例…...

通过vue-pdf和print-js实现PDF和图片在线预览

npm install vue-pdf npm install print-js <template><div><!-- PDF 预览模态框 --><a-modal:visible"showDialog":footer"null"cancel"handleCancel":width"800":maskClosable"true":keyboard"…...

RxJS 核心操作符详细用法示例

1. Observable 详细用法 Observable 是 RxJS 的核心概念&#xff0c;代表一个可观察的数据流。 创建和订阅 Observable import { Observable } from "rxjs";// 1. 创建Observable const myObservable new Observable(subscriber > {// 发出三个值subscriber.n…...

视频监控管理平台EasyCVR结合AI分析技术构建高空抛物智能监控系统,筑牢社区安全防护网

高空抛物严重威胁居民生命安全与公共秩序&#xff0c;传统监管手段存在追责难、威慑弱等问题。本方案基于EasyCVR视频监控与AI视频分析技术&#xff08;智能分析网关&#xff09;&#xff0c;构建高空抛物智能监控系统&#xff0c;实现24小时实时监测、智能识别与精准预警&…...

2.2.1 05年T1复习

引言 从现在进去考研英语基础阶段的进阶&#xff0c;主要任务还是05-09年阅读真题的解题&#xff0c;在本阶段需要注意正确率。阅读最后目标&#xff1a;32-34分&#xff0c;也就是每年真题最多错四个。 做题步骤&#xff1a; 1. 预习&#xff1a;读题干并找关键词 做题&#…...

Python-11(集合)

与字典类似&#xff0c;集合最大的特点就是唯一性。集合中所有的元素都应该是独一无二的&#xff0c;并且也是无序的。 创建集合 使用花括号 set {"python","Java"} print(type(set)) 使用集合推导式 set {s for s in "python"} print(set…...

钉钉开发之AI消息和卡片交互开发文档收集

AI消息和卡片交互开发文档 智能交互接口能力介绍 AI助理发消息&#xff08;主动直接发送模式 AI 助理发消息 - 主动发送模式 AI 助理发消息 - 回复消息模式 AI 助理发消息 - Webhook 回复消息模式 Stream 模式响应卡片回传请求事件 upload-media-files AI 助理发消息&a…...

JMeter 教程:正则表达式提取器提取 JSON 字段数据

目录 JMeter 教程&#xff1a;正则表达式提取器提取 JSON 字段数据【简单实用】 ✅ 目的说明 &#x1f4c4; 示例场景 &#x1f6e0;️ 操作步骤 第一步&#xff1a;发送 HTTP 请求 第二步&#xff1a;添加正则表达式提取器 第三步&#xff1a;使用提取变量 ✅ 正则表达…...

Opixs: Fluxim推出的全新显示仿真模拟软件

Opixs 是 Fluxim 最新研发的显示仿真模拟软件&#xff0c;旨在应对当今显示技术日益复杂的挑战。通过 Opixs&#xff0c;研究人员和工程师可以在制造前&#xff0c;设计并验证 新的像素架构&#xff0c;从而找出更功节能、色彩表现更优的布局方案。 Opixs 适用于学术研究和工业…...

[数据集]无人机视角检测分割数据集合集

数据集名称无人机海洋或河道水上监测检测数据集VOCYOLO格式2903张6类别无人机热红外视角人车检测数据集VOCYOLO格式2866张5类别无人机拍摄红外图像光伏板缺陷检测数据集VOCYOLO格式2723张9类别无人机视角搜索和救援失踪被困人员检测数据集VOCYOLO格式1976张6类别无人机视角垃圾…...

佰力博与您探讨PVDF薄膜极化特性及其影响因素

PVDF&#xff08;聚偏氟乙烯&#xff09;薄膜的极化是其压电性能形成的关键步骤&#xff0c;通过极化处理可以显著提高其压电系数和储能能力。极化过程涉及多种方法和条件&#xff0c;以下从不同角度详细说明PVDF薄膜的极化特性及其影响因素。 1、极化方法 热极化&#xff1a;…...

C++ std::find() 函数全解析

std::find()是C标准库中用于线性查找的基础算法&#xff0c;属于<algorithm>头文件&#xff0c;可应用于任何支持迭代器的容器。 一、函数原型与参数 template< class InputIt, class T > InputIt find( InputIt first, InputIt last, const T& value );​​…...

自动获取ip地址安全吗?如何自动获取ip地址

在数字化网络环境中&#xff0c;IP地址的获取方式直接影响设备连接的便捷性与安全性。自动获取IP地址&#xff08;通过DHCP协议&#xff09;虽简化了配置流程&#xff0c;但其安全性常引发用户疑虑。那么&#xff0c;自动获取IP地址安全吗&#xff1f;如何自动获取IP地址&#…...

STM32:深度解析RS-485总线与SP3485芯片

32个设备 知识点1【RS-485的简介】 RS-485是一种物理层差分总线标准&#xff0c;在串口的基础上演变而来&#xff1b; 两者虽然不在同一层次上直接对等&#xff0c;但在实际系统中&#xff0c;往往使用RS-485驱动差分总线&#xff0c;将USART转换为适合长距离、多点通信的物…...

亚马逊搜索代理: 终极指南

文章目录 前言一、为什么需要代理来搜索亚马逊二、如何选择正确的代理三、搜索亚马逊的最佳代理类型四、为亚马逊搜索设置代理五、常见挑战及克服方法六、亚马逊搜索的替代方法总结 前言 在没有代理的情况下搜索亚马逊会导致 IP 禁止、验证码和速度限制&#xff0c;从而使数据…...

QGraphicsView界面的坑(fitInView()函数没反应)

QGraphicsView本身是特别灵活的一种ui&#xff0c;能够自由响应各种动态操作。不过它最大的问题就是在加载好图像以后&#xff0c;将图像自适应贴合到界面大小的时候&#xff08;fitInView()函数&#xff09;没有反应。 这是因为fitInView函数在执行的时候&#xff0c;需要计算…...

【Python正则表达式终极指南】从零到工程级实战

目录 &#x1f31f; 前言&#x1f3d7;️ 技术背景与价值&#x1fa79; 当前技术痛点&#x1f6e0;️ 解决方案概述&#x1f465; 目标读者说明 &#x1f9e0; 一、技术原理剖析&#x1f4ca; 核心概念图解&#x1f4a1; 核心作用讲解&#x1f527; 关键技术模块说明⚖️ 技术选…...

leetcode 算法每日一题 #1

#1 &#xff01; 题目 3355. 零数组变换 I 中等 相关标签 相关企业 提示 给定一个长度为 n 的整数数组 nums 和一个二维数组 queries&#xff0c;其中 queries[i] [li, ri]。对于每个查询 queries[i]&#xff1a;在 nums 的下标范围 [li, ri] 内选择一个下标 子集。 将选中的…...

用matlab提取abaqus odb文件中的节点信息

在MATLAB中提取Abaqus ODB文件中的节点信息&#xff0c;可以通过以下几种方法实现&#xff1a; 方法1&#xff1a;使用MATLAB的ABAQUS Interface工具箱 https://wenku.csdn.net/answer/77axwtqnys 可以参考这个 MATLAB的ABAQUS Interface工具箱提供了直接读取ODB文件的功能。…...

Spring Bean 注册到容器的方式

Spring Bean 注册到容器的方式主要包括以下几种&#xff1a; 基于 XML 的配置 使用 XML 文件配置 Bean&#xff0c;并定义 Bean 的依赖关系。 基于 Component 注解及其衍生注解 使用注解如 Component、Service、Controller、Repository 等进行配置。 基于 Configuration 和…...

1537. 【中山市第十一届信息学邀请赛决赛】未命名 (noname)

题目描述 这是一个独一无二的世界&#xff0c;所以有 N 张写有互不相同的自然数的卡片&#xff0c;第 i 张卡片写着 Ai &#xff0c;现在你得到了一个未命名的空白卡片&#xff0c;想在上面写上一个自然数 x 满足以下条件&#xff1a; 1.x 不等于任意一张卡片上的数字。 2.x 可…...

数据库三范式详解与应用建议

数据库三范式&#xff08;Normalization&#xff09;是关系型数据库设计的核心原则&#xff0c;旨在减少数据冗余、提高数据一致性&#xff0c;并避免插入、更新和删除异常。以下是三范式的详细说明&#xff1a; 第一范式&#xff08;1NF&#xff09; 核心要求&#xff1a;确保…...