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

抽象工厂模式详解

1. 引言

1.1 设计模式概述

设计模式(Design Patterns)是软件开发中解决常见问题的一种最佳实践。它们通过总结经验,提供了一套被验证有效的代码结构和设计原则,帮助开发者提高代码的可维护性、可重用性和可扩展性。

设计模式主要分为以下三类:

  1. 创建型模式(Creational Patterns):关注对象的创建过程,帮助开发者以一种灵活和可扩展的方式来创建对象。这类模式包括工厂方法、抽象工厂、单例、建造者和原型模式。

  2. 结构型模式(Structural Patterns):关注对象和类的结构组合,以便实现新的功能。这类模式包括适配器、桥接、组合、装饰、外观、享元和代理模式。

  3. 行为型模式(Behavioral Patterns):专注于对象间的责任分配和通信方式,使得对象间的交互更灵活。这类模式包括责任链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略、模板方法和访问者模式。

通过设计模式的合理运用,开发者可以有效提升系统的模块化、灵活性以及代码质量。设计模式不仅仅是实现代码的技巧,更是一种应对复杂软件架构的思维方式。

1.2 抽象工厂模式简介

**抽象工厂模式(Abstract Factory Pattern)**是创建型模式之一,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。抽象工厂模式通过为每个产品族定义一组接口(抽象工厂),并且将这些接口的实现(具体工厂)延迟到子类中,实现不同产品族的创建。

核心思想

  • 产品族和产品等级结构:抽象工厂模式专注于生产一组相关的产品,例如跨平台应用中同一风格的 UI 组件,可以属于同一产品族。
  • 隐藏具体类:客户端不需要知道具体类的名称或实现方式,只需要与抽象工厂和抽象产品接口交互,从而实现了解耦。

主要角色

  1. 抽象工厂(AbstractFactory):定义创建一系列相关产品的接口。
  2. 具体工厂(ConcreteFactory):实现抽象工厂接口,提供具体产品的实例。
  3. 抽象产品(AbstractProduct):定义产品的通用接口。
  4. 具体产品(ConcreteProduct):实现抽象产品接口,提供产品的具体实现。

适用性

  • 需要创建一组相关或相互依赖的对象,并且需要确保它们的创建方式和使用场景一致。
  • 系统不希望依赖于具体类的实现,而是希望通过抽象来创建对象,达到对扩展开放、对修改封闭的效果。

1.3 抽象工厂模式在软件开发中的重要性

抽象工厂模式在软件开发中非常重要,其主要优势体现在以下几个方面:

  1. 解决产品族的兼容性问题:抽象工厂模式通过统一的接口,确保一组相关产品在使用时的兼容性。例如,在跨平台开发中,可以通过抽象工厂模式来创建适应不同操作系统的 UI 组件,确保各组件在不同平台的风格一致性。

  2. 提高代码的可扩展性:通过定义产品族的接口,抽象工厂模式使得新产品族的添加变得简单。只需要添加新的具体工厂和具体产品类,而不需要修改现有代码,符合开闭原则(Open-Closed Principle)。

  3. 解耦创建和使用:抽象工厂模式将产品的创建过程与使用过程解耦,使得客户端代码只需依赖于抽象接口,而不需要依赖于具体类。这种解耦提高了系统的灵活性,方便代码重用和维护。

  4. 简化客户端代码:抽象工厂模式使得客户端代码不需要知道创建过程的细节,提供了更清晰的代码结构。客户端只需调用抽象工厂接口,获取相关产品实例,而不需要关心具体产品的实现和初始化。

  5. 广泛应用于不同的系统架构:抽象工厂模式在各种系统架构中都得到了广泛应用,例如跨平台的 UI 框架、多数据库支持的持久层架构、分布式系统中的服务接口适配等。

在实际开发中,抽象工厂模式通过实现高度的模块化设计,促进了代码的重用和灵活性,使得开发者可以轻松地适应需求变化和系统扩展。因此,掌握抽象工厂模式的应用和扩展,是编写高质量可维护代码的重要技能。

2. 抽象工厂模式详解

2.1 模式定义

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式通过定义一组抽象接口,将创建产品对象的过程交由具体工厂类来实现,使得客户端可以通过抽象接口与工厂和产品交互。

核心思想

抽象工厂模式的核心在于提供一个创建“产品族”的接口,且保证产品族中创建的对象相互兼容。例如,跨平台的 UI 框架可以使用抽象工厂模式,为每种操作系统提供一组特定的界面元素。

主要角色

  1. 抽象工厂:声明创建一组相关产品的接口。
  2. 具体工厂:实现抽象工厂接口,提供具体产品的创建。
  3. 抽象产品:定义产品的公共接口。
  4. 具体产品:实现抽象产品接口,为具体的产品实现。

2.2 模式结构

抽象工厂模式由四个主要角色组成,每个角色在模式中承担不同的职责:

2.2.1 抽象工厂(AbstractFactory)角色

抽象工厂是一个接口或抽象类,用于声明创建不同产品的方法。它负责定义创建一系列相关产品的接口,而不指定具体产品的实现。

// 抽象工厂接口
public interface AbstractFactory {AbstractProductA createProductA();AbstractProductB createProductB();
}

2.2.2 具体工厂(ConcreteFactory)角色

具体工厂实现了抽象工厂接口,负责创建具体产品的实例。每个具体工厂对应一个具体产品族(即一组相关的产品),并提供实现不同产品接口的实例。

// 具体工厂A
public class ConcreteFactoryA implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA1();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB1();}
}// 具体工厂B
public class ConcreteFactoryB implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA2();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB2();}
}

2.2.3 抽象产品(AbstractProduct)角色

抽象产品是一个接口或抽象类,用于定义产品的通用行为。它为具体产品提供了统一的规范,确保不同具体产品具有相同的接口。

// 抽象产品A
public interface AbstractProductA {void use();
}// 抽象产品B
public interface AbstractProductB {void operate();
}

2.2.4 具体产品(ConcreteProduct)角色

具体产品类实现了抽象产品接口,提供具体产品的功能实现。每个具体产品对应一个具体工厂,并且是产品族的一部分。

// 具体产品A1
public class ConcreteProductA1 implements AbstractProductA {@Overridepublic void use() {System.out.println("使用产品A1");}
}// 具体产品B1
public class ConcreteProductB1 implements AbstractProductB {@Overridepublic void operate() {System.out.println("操作产品B1");}
}// 具体产品A2
public class ConcreteProductA2 implements AbstractProductA {@Overridepublic void use() {System.out.println("使用产品A2");}
}// 具体产品B2
public class ConcreteProductB2 implements AbstractProductB {@Overridepublic void operate() {System.out.println("操作产品B2");}
}

2.3 模式的特点

抽象工厂模式具有以下特点:

  1. 产品族管理:抽象工厂模式专注于创建一组相关或相互依赖的对象,能够确保同一产品族中的产品具有一致的风格或特性。

  2. 解耦创建和使用:抽象工厂模式将产品的创建过程和使用过程解耦,客户端只需依赖于抽象接口,避免了与具体产品类的直接耦合。

  3. 扩展性强:新增产品族时,可以通过增加新的具体工厂来实现,无需修改现有代码,符合开闭原则。

  4. 隐藏产品具体类:客户端只需知道抽象工厂和抽象产品的接口,而不需要知道具体类的名称,增强了代码的灵活性和封装性。

2.4 抽象工厂模式的流程图

抽象工厂模式的流程如下:

  1. 客户端(Client):调用抽象工厂的接口来获取具体产品。
  2. 抽象工厂(AbstractFactory):声明创建产品的方法,为一系列相关产品的创建提供接口。
  3. 具体工厂(ConcreteFactory):实现抽象工厂的接口,负责实例化具体产品。
  4. 抽象产品(AbstractProduct):定义产品的接口,为具体产品提供规范。
  5. 具体产品(ConcreteProduct):实现抽象产品的接口,提供具体产品的功能。

2.5 与工厂方法模式的比较

相同点

  • 创建型模式:抽象工厂模式和工厂方法模式都是创建型模式,关注对象的创建过程。
  • 解耦创建和使用:两个模式都解耦了产品的创建和使用,使客户端代码不直接依赖于具体产品类。

不同点

  1. 产品族和产品等级结构

    • 工厂方法模式:适用于单一产品的创建,即单一产品等级结构。
    • 抽象工厂模式:适用于创建多个相关产品,即多个产品等级结构或产品族。
  2. 复杂度

    • 工厂方法模式:结构相对简单,适合单一产品的创建。
    • 抽象工厂模式:结构较复杂,适合产品族的创建。
  3. 适用性

    • 工厂方法模式:当系统仅涉及单个产品的创建,且产品种类较少时,适合使用工厂方法模式。
    • 抽象工厂模式:当系统需要创建多个产品族的对象,且这些产品族之间有关系时,适合使用抽象工厂模式。

2.6 抽象工厂模式的优缺点

优点

  1. 易于扩展产品族:可以通过增加新的具体工厂类,轻松扩展新的产品族,而无需修改现有代码。

  2. 产品族的一致性:通过抽象工厂模式,可以确保同一产品族的产品具有相同的风格或兼容性。

  3. 降低耦合度:客户端代码依赖于抽象接口,而不依赖于具体产品类,增强了系统的可维护性和灵活性。

  4. 遵循开闭原则:可以在不修改现有代码的情况下,通过增加新工厂和新产品实现扩展,符合开闭原则。

缺点

  1. 难以扩展新产品:添加新产品(例如,增加新的产品 C)需要修改抽象工厂接口,进而需要修改所有具体工厂,违背了开闭原则。

  2. 增加系统复杂性:抽象工厂模式涉及多个抽象类和接口,对于简单的产品创建需求,使用抽象工厂模式可能导致设计过度复杂。

  3. 扩展难度增加:当系统需要支持更多产品族和产品等级结构时,可能需要增加大量的具体类和接口,导致代码维护成本上升。

3. 抽象工厂模式的使用场景及业务实例

3.1 使用场景概述

抽象工厂模式在软件开发中适用于需要创建一组相关或相互依赖的对象,且希望通过一个统一的接口来管理创建过程的场景。它特别适合以下情况:

  1. 跨平台应用开发:在跨平台应用中,不同平台的 UI 组件风格可能有所不同,例如 Windows 和 macOS 具有不同的按钮、文本框等组件。这种情况下,可以通过抽象工厂模式创建特定平台风格的组件族。

  2. 数据库访问层的切换:不同数据库可能需要不同的连接配置和查询语法,通过抽象工厂模式可以根据需要动态地创建相应的数据库访问组件,方便支持多种数据库类型。

  3. 游戏开发中的族系和职业:在一些游戏中,不同族系的职业具有特定的技能或装备类型,可以通过抽象工厂模式管理不同族系的职业和属性的创建。

接下来,通过三个实际的业务实例展示抽象工厂模式的应用。

3.2 业务实例一:跨平台界面库

3.2.1 需求分析

在跨平台应用开发中,我们希望界面组件能够适配不同的操作系统,例如 Windows 和 macOS。每个平台的按钮、文本框、菜单等 UI 元素具有不同的视觉风格。我们需要一套能够根据系统平台动态选择并创建组件的解决方案,使得不同平台的界面风格保持一致。

需求

  • 提供 Windows 和 macOS 风格的 UI 组件,如按钮和文本框。
  • 能够通过统一的接口创建不同风格的组件。
  • 确保同一平台的组件保持风格一致。

3.2.2 设计方案

为满足需求,我们可以使用抽象工厂模式。具体设计如下:

  1. 抽象工厂(UIFactory):定义创建按钮和文本框的接口。
  2. 具体工厂(WindowsUIFactory 和 MacOSUIFactory):分别实现创建 Windows 和 macOS 风格的组件。
  3. 抽象产品(Button 和 TextField):定义按钮和文本框的接口。
  4. 具体产品(WindowsButton、WindowsTextField、MacOSButton、MacOSTextField):实现不同平台风格的按钮和文本框。

3.2.3 抽象工厂模式的应用

代码实现

// 抽象产品:按钮
public interface Button {void click();
}// 抽象产品:文本框
public interface TextField {void input(String text);
}// 具体产品:Windows 按钮
public class WindowsButton implements Button {@Overridepublic void click() {System.out.println("Windows 风格按钮被点击");}
}// 具体产品:Windows 文本框
public class WindowsTextField implements TextField {@Overridepublic void input(String text) {System.out.println("Windows 文本框输入:" + text);}
}// 具体产品:macOS 按钮
public class MacOSButton implements Button {@Overridepublic void click() {System.out.println("macOS 风格按钮被点击");}
}// 具体产品:macOS 文本框
public class MacOSTextField implements TextField {@Overridepublic void input(String text) {System.out.println("macOS 文本框输入:" + text);}
}// 抽象工厂:UI 工厂
public interface UIFactory {Button createButton();TextField createTextField();
}// 具体工厂:Windows UI 工厂
public class WindowsUIFactory implements UIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextField createTextField() {return new WindowsTextField();}
}// 具体工厂:macOS UI 工厂
public class MacOSUIFactory implements UIFactory {@Overridepublic Button createButton() {return new MacOSButton();}@Overridepublic TextField createTextField() {return new MacOSTextField();}
}// 客户端代码
public class Client {public static void main(String[] args) {UIFactory factory = new WindowsUIFactory(); // 可替换为 MacOSUIFactoryButton button = factory.createButton();TextField textField = factory.createTextField();button.click();            // 输出:Windows 风格按钮被点击textField.input("Hello");  // 输出:Windows 文本框输入:Hello}
}

总结

  • 通过抽象工厂模式,我们确保了同一平台的 UI 组件具有一致的视觉风格。
  • 客户端代码不需要知道具体产品的实现,保持了代码的灵活性和可扩展性。

3.3 业务实例二:数据库访问层

3.3.1 需求分析

在开发数据库访问层时,不同数据库(如 MySQL、Oracle、SQL Server 等)可能需要不同的连接配置和查询操作。例如,不同的数据库连接方法和查询语法可能有所不同。为了确保系统的灵活性,我们需要一种方式,根据配置来选择和创建特定数据库的访问组件。

需求

  • 支持多种数据库的访问,如 MySQL 和 Oracle。
  • 提供统一的接口创建数据库连接和查询操作。
  • 能够根据配置或参数动态选择数据库类型。

3.3.2 设计方案

我们可以使用抽象工厂模式来设计数据库访问层。

  1. 抽象工厂(DatabaseFactory):定义创建数据库连接和查询对象的接口。
  2. 具体工厂(MySQLDatabaseFactory 和 OracleDatabaseFactory):实现创建特定数据库的连接和查询对象。
  3. 抽象产品(Connection 和 Query):定义连接和查询的接口。
  4. 具体产品(MySQLConnection、MySQLQuery、OracleConnection、OracleQuery):实现不同数据库的连接和查询逻辑。

3.3.3 抽象工厂模式的应用

代码实现

// 抽象产品:数据库连接
public interface Connection {void connect();
}// 抽象产品:查询
public interface Query {void execute(String sql);
}// 具体产品:MySQL 连接
public class MySQLConnection implements Connection {@Overridepublic void connect() {System.out.println("连接到 MySQL 数据库");}
}// 具体产品:MySQL 查询
public class MySQLQuery implements Query {@Overridepublic void execute(String sql) {System.out.println("执行 MySQL 查询:" + sql);}
}// 具体产品:Oracle 连接
public class OracleConnection implements Connection {@Overridepublic void connect() {System.out.println("连接到 Oracle 数据库");}
}// 具体产品:Oracle 查询
public class OracleQuery implements Query {@Overridepublic void execute(String sql) {System.out.println("执行 Oracle 查询:" + sql);}
}// 抽象工厂:数据库工厂
public interface DatabaseFactory {Connection createConnection();Query createQuery();
}// 具体工厂:MySQL 数据库工厂
public class MySQLDatabaseFactory implements DatabaseFactory {@Overridepublic Connection createConnection() {return new MySQLConnection();}@Overridepublic Query createQuery() {return new MySQLQuery();}
}// 具体工厂:Oracle 数据库工厂
public class OracleDatabaseFactory implements DatabaseFactory {@Overridepublic Connection createConnection() {return new OracleConnection();}@Overridepublic Query createQuery() {return new OracleQuery();}
}// 客户端代码
public class Client {public static void main(String[] args) {DatabaseFactory factory = new MySQLDatabaseFactory(); // 可替换为 OracleDatabaseFactoryConnection connection = factory.createConnection();Query query = factory.createQuery();connection.connect();                 // 输出:连接到 MySQL 数据库query.execute("SELECT * FROM table"); // 输出:执行 MySQL 查询:SELECT * FROM table}
}

总结

  • 通过抽象工厂模式,客户端代码能够灵活地支持不同的数据库类型。
  • 扩展新的数据库类型时,只需添加新的具体工厂和具体产品类,符合开闭原则。

3.4 业务实例三:游戏中的族系与职业

3.4.1 需求分析

在一些游戏中,玩家可以选择不同的族系(如人类、精灵等)和职业(如战士、法师等)。不同族系的职业拥有不同的属性和技能。例如,人类的战士和精灵的战士具有不同的技能或装备。我们需要一种方式来创建特定族系的职业对象,以便更好地管理职业和族系的组合。

需求

  • 提供多种族系(如人类和精灵)和职业(如战士和法师)的组合。
  • 根据玩家的选择创建不同族系的职业对象。
  • 能够确保同一族系的职业具有一致

的风格或特性。

3.4.2 设计方案

我们可以使用抽象工厂模式来设计游戏中的族系和职业管理系统。

  1. 抽象工厂(RaceFactory):定义创建战士和法师对象的接口。
  2. 具体工厂(HumanFactory 和 ElfFactory):实现创建特定族系的战士和法师对象。
  3. 抽象产品(Warrior 和 Mage):定义战士和法师的接口。
  4. 具体产品(HumanWarrior、HumanMage、ElfWarrior、ElfMage):实现不同族系的战士和法师。

3.4.3 抽象工厂模式的应用

代码实现

// 抽象产品:战士
public interface Warrior {void attack();
}// 抽象产品:法师
public interface Mage {void castSpell();
}// 具体产品:人类战士
public class HumanWarrior implements Warrior {@Overridepublic void attack() {System.out.println("人类战士使用剑攻击");}
}// 具体产品:人类法师
public class HumanMage implements Mage {@Overridepublic void castSpell() {System.out.println("人类法师施放火球术");}
}// 具体产品:精灵战士
public class ElfWarrior implements Warrior {@Overridepublic void attack() {System.out.println("精灵战士使用弓箭攻击");}
}// 具体产品:精灵法师
public class ElfMage implements Mage {@Overridepublic void castSpell() {System.out.println("精灵法师施放冰冻术");}
}// 抽象工厂:种族工厂
public interface RaceFactory {Warrior createWarrior();Mage createMage();
}// 具体工厂:人类工厂
public class HumanFactory implements RaceFactory {@Overridepublic Warrior createWarrior() {return new HumanWarrior();}@Overridepublic Mage createMage() {return new HumanMage();}
}// 具体工厂:精灵工厂
public class ElfFactory implements RaceFactory {@Overridepublic Warrior createWarrior() {return new ElfWarrior();}@Overridepublic Mage createMage() {return new ElfMage();}
}// 客户端代码
public class Client {public static void main(String[] args) {RaceFactory factory = new HumanFactory(); // 可替换为 ElfFactoryWarrior warrior = factory.createWarrior();Mage mage = factory.createMage();warrior.attack();       // 输出:人类战士使用剑攻击mage.castSpell();       // 输出:人类法师施放火球术}
}

总结

  • 抽象工厂模式使得游戏开发者可以轻松管理不同族系的职业组合。
  • 通过新增具体工厂,可以支持新的族系,而无需修改客户端代码。

4. 多语言代码实现

抽象工厂模式在不同的编程语言中实现方式略有不同。以下提供 Java、Python、C#、JavaScript、Go、Rust、Ruby 和 C++ 的代码示例,展示如何在各语言中实现抽象工厂模式。

4.1 Java 实现

4.1.1 抽象工厂与具体工厂

// 抽象工厂接口
public interface UIFactory {Button createButton();TextField createTextField();
}// 具体工厂:Windows 风格工厂
public class WindowsFactory implements UIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextField createTextField() {return new WindowsTextField();}
}// 具体工厂:macOS 风格工厂
public class MacOSFactory implements UIFactory {@Overridepublic Button createButton() {return new MacOSButton();}@Overridepublic TextField createTextField() {return new MacOSTextField();}
}

4.1.2 抽象产品与具体产品

// 抽象产品:按钮
public interface Button {void click();
}// 抽象产品:文本框
public interface TextField {void input(String text);
}// 具体产品:Windows 风格按钮
public class WindowsButton implements Button {@Overridepublic void click() {System.out.println("Windows 风格按钮被点击");}
}// 具体产品:macOS 风格按钮
public class MacOSButton implements Button {@Overridepublic void click() {System.out.println("macOS 风格按钮被点击");}
}// 具体产品:Windows 风格文本框
public class WindowsTextField implements TextField {@Overridepublic void input(String text) {System.out.println("Windows 文本框输入:" + text);}
}// 具体产品:macOS 风格文本框
public class MacOSTextField implements TextField {@Overridepublic void input(String text) {System.out.println("macOS 文本框输入:" + text);}
}

4.1.3 客户端代码

public class Client {public static void main(String[] args) {UIFactory factory = new WindowsFactory(); // 可以替换为 MacOSFactoryButton button = factory.createButton();TextField textField = factory.createTextField();button.click();textField.input("Hello, World!");}
}

4.1.4 运行结果分析

运行结果如下:

Windows 风格按钮被点击
Windows 文本框输入:Hello, World!

4.2 Python 实现

4.2.1 抽象工厂与具体工厂

from abc import ABC, abstractmethod# 抽象工厂
class UIFactory(ABC):@abstractmethoddef create_button(self):pass@abstractmethoddef create_textfield(self):pass# 具体工厂:Windows 风格
class WindowsFactory(UIFactory):def create_button(self):return WindowsButton()def create_textfield(self):return WindowsTextField()# 具体工厂:macOS 风格
class MacOSFactory(UIFactory):def create_button(self):return MacOSButton()def create_textfield(self):return MacOSTextField()

4.2.2 抽象产品与具体产品

# 抽象产品:按钮
class Button(ABC):@abstractmethoddef click(self):pass# 抽象产品:文本框
class TextField(ABC):@abstractmethoddef input(self, text):pass# 具体产品:Windows 按钮
class WindowsButton(Button):def click(self):print("Windows 按钮被点击")# 具体产品:macOS 按钮
class MacOSButton(Button):def click(self):print("macOS 按钮被点击")# 具体产品:Windows 文本框
class WindowsTextField(TextField):def input(self, text):print(f"Windows 文本框输入:{text}")# 具体产品:macOS 文本框
class MacOSTextField(TextField):def input(self, text):print(f"macOS 文本框输入:{text}")

4.2.3 客户端代码

def client(factory: UIFactory):button = factory.create_button()textfield = factory.create_textfield()button.click()textfield.input("Hello, World!")# 使用 Windows 风格
client(WindowsFactory())# 使用 macOS 风格
client(MacOSFactory())

4.2.4 运行结果分析

运行结果如下:

Windows 按钮被点击
Windows 文本框输入:Hello, World!
macOS 按钮被点击
macOS 文本框输入:Hello, World!

4.3 C# 实现

4.3.1 抽象工厂与具体工厂

// 抽象工厂
public interface UIFactory {Button CreateButton();TextField CreateTextField();
}// 具体工厂:Windows 风格
public class WindowsFactory : UIFactory {public Button CreateButton() => new WindowsButton();public TextField CreateTextField() => new WindowsTextField();
}// 具体工厂:macOS 风格
public class MacOSFactory : UIFactory {public Button CreateButton() => new MacOSButton();public TextField CreateTextField() => new MacOSTextField();
}

4.3.2 抽象产品与具体产品

// 抽象产品:按钮
public interface Button {void Click();
}// 抽象产品:文本框
public interface TextField {void Input(string text);
}// 具体产品:Windows 按钮
public class WindowsButton : Button {public void Click() {Console.WriteLine("Windows 按钮被点击");}
}// 具体产品:macOS 按钮
public class MacOSButton : Button {public void Click() {Console.WriteLine("macOS 按钮被点击");}
}// 具体产品:Windows 文本框
public class WindowsTextField : TextField {public void Input(string text) {Console.WriteLine($"Windows 文本框输入:{text}");}
}// 具体产品:macOS 文本框
public class MacOSTextField : TextField {public void Input(string text) {Console.WriteLine($"macOS 文本框输入:{text}");}
}

4.3.3 客户端代码

class Client {static void Main() {UIFactory factory = new WindowsFactory(); // 可以替换为 MacOSFactoryButton button = factory.CreateButton();TextField textField = factory.CreateTextField();button.Click();textField.Input("Hello, World!");}
}

4.3.4 运行结果分析

运行结果如下:

Windows 按钮被点击
Windows 文本框输入:Hello, World!

4.4 JavaScript 实现

4.4.1 抽象工厂与具体工厂

class UIFactory {createButton() {}createTextField() {}
}class WindowsFactory extends UIFactory {createButton() {return new WindowsButton();}createTextField() {return new WindowsTextField();}
}class MacOSFactory extends UIFactory {createButton() {return new MacOSButton();}createTextField() {return new MacOSTextField();}
}

4.4.2 抽象产品与具体产品

class Button {click() {}
}class TextField {input(text) {}
}class WindowsButton extends Button {click() {console.log("Windows 按钮被点击");}
}class MacOSButton extends Button {click() {console.log("macOS 按钮被点击");}
}class WindowsTextField extends TextField {input(text) {console.log(`Windows 文本框输入:${text}`);}
}class MacOSTextField extends TextField {input(text) {console.log(`macOS 文本框输入:${text}`);}
}

4.4.3 客户端代码

function client(factory) {const button = factory.createButton();const textField = factory.createTextField();button.click();textField.input("Hello, World!");
}client(new WindowsFactory());
client(new MacOSFactory());

4.4.4 运行结果分析

运行结果如下:

Windows 按钮被点击
Windows 文本框输入:Hello, World!
macOS 按钮被点击
macOS 文本框输入:Hello, World!

4.5 Go 实现

4.5.1 抽象工厂与具体工厂

package mainimport "fmt"// 抽象工厂接口
type UIFactory interface {CreateButton() ButtonCreateTextField() TextField
}// 具体工厂:Windows 风格
type WindowsFactory struct{}func (f *WindowsFactory) CreateButton() Button {return &WindowsButton{}
}func (f *WindowsFactory) CreateTextField() TextField {return &WindowsTextField{}
}// 具体工厂:macOS 风格
type MacOSFactory struct{}func (f *MacOSFactory) CreateButton() Button {return &MacOSButton{}
}func (f *MacOSFactory) CreateTextField() TextField {return &MacOSTextField{}
}

4.5.2 抽象产品与具体产品

// 抽象产品:按钮
type Button interface {Click()
}// 抽象产品:文本框
type TextField interface {Input(text string)
}// 具体产品:Windows 按钮
type WindowsButton struct{}func (b *WindowsButton) Click() {fmt.Println("Windows 按钮被点击")
}// 具体产品:macOS 按钮
type MacOSButton struct{}func (b *MacOSButton) Click() {fmt.Println("macOS 按钮被点击")
}// 具体产品:Windows 文本框
type WindowsTextField struct{}func (t *WindowsTextField) Input(text string) {fmt.Printf("Windows 文本框输入:%s\n", text)
}// 具体产品:macOS 文本框
type MacOSTextField struct{}func (t *MacOSTextField) Input(text string) {fmt.Printf("macOS 文本框输入:%s\n", text)
}

4.5.3 客户端代码

func main() {var factory UIFactoryfactory = &WindowsFactory{} // 可替换为 &MacOSFactory{}button := factory.CreateButton()textField := factory.CreateTextField()button.Click()textField.Input("Hello, World!")
}

4.5.4 运行结果分析

运行结果如下:

Windows 按钮被点击
Windows 文本框输入:Hello, World!

4.6 Rust 实现

4.6.1 抽象工厂与具体工厂

// 抽象工厂
trait UIFactory {fn create_button(&self) -> Box<dyn Button>;fn create_textfield(&self) -> Box<dyn TextField>;
}// 具体工厂:Windows 风格
struct WindowsFactory;impl UIFactory for WindowsFactory {fn create_button(&self) -> Box<dyn Button> {Box::new(WindowsButton)}fn create_textfield(&self) -> Box<dyn TextField> {Box::new(WindowsTextField)}
}// 具体工厂:macOS 风格
struct MacOSFactory;impl UIFactory for MacOSFactory {fn create_button(&self) -> Box<dyn Button> {Box::new(MacOSButton)}fn create_textfield(&self) -> Box<dyn TextField> {Box::new(MacOSTextField)}
}

4.6.2 抽象产品与具体产品

// 抽象产品:按钮
trait Button {fn click(&self);
}// 抽象产品:文本框
trait TextField {fn input(&self, text: &str);
}// 具体产品:Windows 按钮
struct WindowsButton;impl Button for WindowsButton {fn click(&self) {println!("Windows 按钮被点击");}
}// 具体产品:macOS 按钮
struct MacOSButton;impl Button for MacOSButton {fn click(&self) {println!("macOS 按钮被点击");}
}// 具体产品:Windows 文本框
struct WindowsTextField;impl TextField for WindowsTextField {fn input(&self, text: &str) {println!("Windows 文本框输入:{}", text);}
}// 具体产品:macOS 文本框
struct MacOSTextField;impl TextField for MacOSTextField {fn input(&self, text: &str) {println!("macOS 文本框输入:{}", text);}
}

4.6.3 客户端代码

fn main() {let factory: Box<dyn UIFactory> = Box::new(WindowsFactory); // 可替换为 Box::new(MacOSFactory)let button = factory.create_button();let text_field = factory.create_textfield();button.click();text_field.input("Hello, World!");
}

4.6.4 运行结果分析

运行结果如下:

Windows 按钮被点击
Windows 文本框输入:Hello, World!

4.7 Ruby 实现

4.7.1 抽象工厂与具体工厂

# 抽象工厂
class UIFactorydef create_buttonraise NotImplementedError, '必须实现该方法'enddef create_text_fieldraise NotImplementedError, '必须实现该方法'end
end# 具体工厂:Windows 风格
class WindowsFactory < UIFactorydef create_buttonWindowsButton.newenddef create_text_fieldWindowsTextField.newend
end# 具体工厂:macOS 风格
class MacOSFactory < UIFactorydef create_buttonMacOSButton.newenddef create_text_fieldMacOSTextField.newend
end

4.7.2 抽象产品与具体产品

# 抽象产品:按钮
class Buttondef clickraise NotImplementedError, '必须实现该方法'end
end# 抽象产品:文本框
class TextFielddef input(text)raise NotImplementedError, '必须实现该方法'end
end# 具体产品:Windows 按钮
class WindowsButton < Buttondef clickputs 'Windows 按钮被点击'end
end# 具体产品:macOS 按钮
class MacOSButton < Buttondef clickputs 'macOS 按钮被点击'end
end# 具体产品:Windows 文本框
class WindowsTextField < TextFielddef input(text)puts "Windows 文本框输入:#{text}"end
end# 具体产品:macOS 文本框
class MacOSTextField < TextFielddef input(text)puts "macOS 文本框输入:#{text}"end
end

4.7.3 客户端代码

def client(factory)button = factory.create_buttontext_field = factory.create_text_fieldbutton.clicktext_field.input("Hello, World!")
end# 使用 Windows 风格
client(WindowsFactory.new)# 使用 macOS 风格
client(MacOSFactory.new)

4.7.4 运行结果分析

运行结果如下:

Windows 按钮被点击
Windows 文本框输入:Hello, World!
macOS 按钮被点击
macOS 文本框输入:Hello, World!

4.8 C++ 实现

4.8.1 抽象工厂与具体工厂

#include <iostream>
#include <memory>
#include <string>// 抽象工厂
class UIFactory {
public:virtual std::unique_ptr<Button> createButton() const = 0;virtual std::unique_ptr<TextField> createTextField() const = 0;virtual ~UIFactory() = default;
};// 具体工厂:Windows 风格
class WindowsFactory : public UIFactory {
public:std::unique_ptr<Button> createButton() const override {return std::make_unique<WindowsButton>();}std::unique_ptr<TextField> createTextField() const override {return std::make_unique<WindowsTextField>();}
};// 具体工厂:macOS 风格
class MacOSFactory : public UIFactory {
public:std::unique_ptr<Button> createButton() const override {return std::make_unique<MacOSButton>();}std::unique_ptr<TextField> createTextField() const override {return std::make_unique<MacOSTextField>();}
};

4.8.2 抽象产品与具体产品

// 抽象产品:按钮
class Button {
public:virtual void click() const = 0;virtual ~Button() = default;
};// 抽象产品:文本框
class TextField {
public:virtual void input(const std::string& text) const = 0;virtual ~TextField() = default;
};// 具体产品:Windows 按钮
class WindowsButton : public Button {
public:void click() const override {std::cout << "Windows 按钮被点击\n";}
};// 具体产品:macOS 按钮
class MacOSButton : public Button {
public:void click() const override {std::cout << "macOS 按钮被点击\n";}
};// 具体产品:Windows 文本框
class WindowsTextField : public TextField {
public:void input(const std::string& text) const override {std::cout << "Windows 文本框输入:" << text << "\n";}
};// 具体产品:macOS 文本框
class MacOSTextField : public TextField {
public:void input(const std::string& text) const override {std::cout << "macOS 文本框输入:" << text << "\n";}
};

4.8.3 客户端代码

int main() {std::unique_ptr<UIFactory> factory = std::make_unique<WindowsFactory>(); // 可替换为 MacOSFactorystd::unique_ptr<Button> button = factory->createButton();std::unique_ptr<TextField> textField = factory->createTextField();button->click();textField->input("Hello, World!");return 0;
}

4.8.4 运行结果分析

运行结果如下:

Windows 按钮被点击
Windows 文本框输入:Hello, World!

5. 抽象工厂模式的扩展与优化

抽象工厂模式提供了一种灵活的产品族创建机制,适用于多种场景。在实际开发中,抽象工厂模式可以根据需求进行扩展和优化,使其更适应复杂系统的需求。以下是几种扩展和优化策略。

5.1 抽象工厂的参数化

概念

参数化工厂是指将参数传递给工厂方法,工厂根据参数值决定创建哪种具体产品。这种方式减少了具体工厂类的数量,并提升了工厂的灵活性,使得单个工厂可以创建不同类型的产品。

实现方式

在抽象工厂的接口中,定义一个接受参数的工厂方法,根据传入的参数创建不同的产品对象。

示例

假设我们有一个 VehicleFactory 工厂类,可以根据参数创建不同类型的车辆:

// 抽象产品
public interface Vehicle {void drive();
}// 具体产品:汽车
public class Car implements Vehicle {@Overridepublic void drive() {System.out.println("驾驶汽车");}
}// 具体产品:卡车
public class Truck implements Vehicle {@Overridepublic void drive() {System.out.println("驾驶卡车");}
}// 参数化工厂
public class VehicleFactory {public Vehicle createVehicle(String type) {if (type.equalsIgnoreCase("Car")) {return new Car();} else if (type.equalsIgnoreCase("Truck")) {return new Truck();}throw new IllegalArgumentException("未知车辆类型");}
}// 客户端代码
public class Client {public static void main(String[] args) {VehicleFactory factory = new VehicleFactory();Vehicle car = factory.createVehicle("Car");car.drive(); // 输出:驾驶汽车Vehicle truck = factory.createVehicle("Truck");truck.drive(); // 输出:驾驶卡车}
}

优势

  • 减少类的数量:不需要为每一种产品类型创建具体的工厂类。
  • 提高灵活性:可以动态选择产品类型,适应更复杂的产品组合需求。

使用场景

  • 产品类型较多且变化频繁:产品类型不固定,且希望减少工厂类的数量。
  • 运行时确定产品类型:在运行时根据参数动态选择产品类型。

5.2 使用配置文件和反射机制

概念

通过配置文件和反射机制,可以在运行时动态加载工厂类和产品类。配置文件定义了具体工厂类和产品类的信息,程序根据配置通过反射创建实例。这样可以有效解耦产品的定义和使用。

实现方式

  1. 配置文件:定义产品和工厂的类名。
  2. 反射机制:读取配置文件中的类名并实例化对象。

示例

假设我们有一个配置文件 config.properties,内容如下:

buttonClass=WindowsButton
textFieldClass=WindowsTextField

读取配置文件并使用反射创建对象:

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;public class ConfigurableFactory {public static Button createButton() {return (Button) createInstance("buttonClass");}public static TextField createTextField() {return (TextField) createInstance("textFieldClass");}private static Object createInstance(String key) {Properties properties = new Properties();try (FileInputStream input = new FileInputStream("config.properties")) {properties.load(input);String className = properties.getProperty(key);Class<?> clazz = Class.forName(className);return clazz.getDeclaredConstructor().newInstance();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("实例化失败");}}
}

优势

  • 动态加载:可以根据配置文件切换产品和工厂,而无需更改代码。
  • 解耦:工厂类和产品类的信息独立于代码,灵活适应需求变化。

使用场景

  • 插件式架构:通过配置文件加载插件,适应不同场景的需求。
  • 产品和工厂的频繁切换:需要根据配置快速更换产品实现。

5.3 与其他设计模式的结合

抽象工厂模式可以与其他设计模式结合使用,以提高系统的灵活性和可扩展性。

5.3.1 与工厂方法模式的结合

概念

抽象工厂模式通常用于创建一组相关的产品,而工厂方法模式用于创建单个产品。通过将抽象工厂中的产品创建方法使用工厂方法模式实现,可以进一步分离具体产品的创建逻辑。

示例
// 抽象工厂
public abstract class UIFactory {public abstract Button createButton();public abstract TextField createTextField();
}// 工厂方法模式实现具体工厂
public class WindowsFactory extends UIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextField createTextField() {return new WindowsTextField();}
}// 产品类实现省略
优势
  • 分层解耦:工厂方法模式和抽象工厂模式结合,将具体产品的创建和产品族的管理分离。
  • 易于扩展:可以单独扩展具体产品或产品族。

5.3.2 与单例模式的结合

概念

在某些场景下,工厂类仅需一个实例即可完成所有操作,这时可以将工厂类设计为单例模式,避免重复创建工厂实例,节省资源。

示例
public class SingletonFactory extends UIFactory {private static SingletonFactory instance = new SingletonFactory();private SingletonFactory() {// 私有构造函数}public static SingletonFactory getInstance() {return instance;}@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic TextField createTextField() {return new WindowsTextField();}
}
优势
  • 资源节约:工厂作为单例存在,避免了重复实例化。
  • 全局访问:可以从系统的任意位置获取工厂实例。

使用场景

  • 工厂无状态:工厂类不保存状态,适合单例管理。
  • 多次调用工厂:当工厂创建频繁,且无状态时,单例可以提升性能。

5.4 实际开发中的注意事项

1. 避免过度设计

  • 适度使用:不要为了使用模式而使用模式,应根据具体需求选择合适的设计。
  • 权衡复杂性和灵活性:抽象工厂模式会增加类的数量和系统复杂性,特别在简单场景中不一定需要使用。

2. 考虑性能影响

  • 反射的开销:反射机制通常会带来性能开销,在高性能要求的场景中需要慎重使用。
  • 对象创建开销:如果对象创建过程非常简单,不一定需要抽象工厂。

3. 结合依赖注入和配置文件

  • 依赖注入:在现代开发中,依赖注入框架(如 Spring)可以很好地管理对象的创建,结合抽象工厂模式可以进一步增强灵活性。
  • 配置驱动:通过配置文件驱动工厂,可以降低代码耦合性和修改成本。

4. 保持代码的可读性和可维护性

  • 命名规范:使用清晰的类名和方法名,便于其他开发者理解工厂和产品的角色。
  • 注释和文档:在工厂方法和产品接口上添加必要的注释,帮助理解设计意图。

5. 测试与调试

  • 单元测试:为工厂方法和具体产品类编写单元测试,确保功能正确性。
  • 日志记录:在工厂创建方法中添加日志,方便调试和排查问题。

6. 多线程与并发

  • 线程安全:在多线程环境中,确保工厂和产品实例的创建是线程安全的。
  • 同步机制:在必要的地方使用同步机制,避免竞态条件的出现。

6. 总结

6.1 抽象工厂模式的适用性

抽象工厂模式在软件开发中是非常实用的设计模式之一,特别适用于以下场景:

  1. 需要创建多个相互关联的产品对象:如 UI 界面不同平台的风格一致性,在客户端只需调用抽象接口,不需要关注产品的具体实现。

  2. 产品族一致性:需要确保创建的对象是兼容的,例如数据库访问模块,不同数据库的连接器和查询对象保持兼容。

  3. 避免直接依赖具体类:在开发过程中尽量与抽象工厂接口和产品接口交互,使得系统具备更高的扩展性和可维护性。

  4. 产品类型稳定但可能扩展更多族类:如果系统产品类型在未来可能会增加,那么抽象工厂模式可以帮助系统更好地应对需求变化。

6.2 如何识别和重构到抽象工厂模式

识别使用场景

可以考虑使用抽象工厂模式的常见特征:

  • 存在多个产品等级结构和产品族:如果在系统中发现创建相关对象时依赖于条件判断,或者有多个独立的工厂类负责不同产品族,可以考虑抽象工厂。
  • 多个产品需要成组出现:如果产品必须同时成组出现,比如跨平台的 UI 组件,或者不同数据库的连接和查询类,则可以使用抽象工厂模式进行重构。
  • 高耦合和复杂性:如果产品的具体类与客户端代码紧密耦合,并且这种耦合增加了系统的复杂性,抽象工厂模式可以帮助简化系统。

重构步骤

  1. 提取公共接口:提取出所有产品的接口或抽象类,将现有的具体产品类实现这些接口。
  2. 创建抽象工厂接口:定义一个抽象工厂接口,声明创建产品的方法。
  3. 实现具体工厂类:为每个产品族创建具体工厂类,实现工厂接口,并实例化对应的具体产品。
  4. 替换客户端代码:在客户端代码中,将直接使用具体类的方式替换为通过抽象工厂接口创建产品。

6.3 模式的未来展望

随着软件开发技术的不断发展,抽象工厂模式的核心思想将保持其重要性,但应用形式可能会发生变化:

  1. 结合依赖注入框架:在现代开发中,依赖注入框架(如 Spring 等)可以自动管理对象的创建,抽象工厂模式可以结合这些框架,用于创建更复杂的产品族。

  2. 动态配置和插件化架构:随着插件化架构的流行,抽象工厂模式可以通过配置驱动产品的选择,在应用启动时根据配置动态加载产品模块,实现插件的动态扩展。

  3. 支持更多编程范式:随着函数式编程的流行,许多语言支持更简洁的对象创建方式,但抽象工厂模式的分层结构和解耦思想依然适用。

  4. 微服务与分布式架构:在微服务和分布式架构中,不同服务之间的接口兼容性可以通过抽象工厂模式的思想进行管理,实现服务接口和实现的解耦。

7. 参考资料

7.1 书籍推荐

  1. 《设计模式:可复用面向对象软件的基础》(Erich Gamma 等)——设计模式的经典之作,详细介绍了包括抽象工厂在内的 23 种模式。

  2. 《Head First 设计模式》(Eric Freeman 等)——通过轻松有趣的方式介绍设计模式,适合初学者入门。

  3. 《Effective Java》(Joshua Bloch)——介绍了 Java 编程中的最佳实践,涵盖了许多设计模式相关的内容。

7.2 在线资源

  1. Refactoring Guru:提供了丰富的设计模式资料和代码示例。

    • 抽象工厂模式
  2. 菜鸟教程:设计模式:提供了设计模式的基础概念和示例代码。

    • 菜鸟教程 - 抽象工厂模式
  3. Stack Overflow:遇到设计模式相关的具体问题时可以在 Stack Overflow 上找到讨论和解答。

    • Stack Overflow

7.3 示例代码下载

所有代码示例已上传至 GitHub,读者可以通过以下链接下载并运行这些代码。

  • GitHub 链接:抽象工厂模式示例代码

以上资源和示例代码可以帮助更好地理解和应用抽象工厂模式,使您在实际项目中灵活地应用该设计模式。

相关文章:

抽象工厂模式详解

1. 引言 1.1 设计模式概述 设计模式&#xff08;Design Patterns&#xff09;是软件开发中解决常见问题的一种最佳实践。它们通过总结经验&#xff0c;提供了一套被验证有效的代码结构和设计原则&#xff0c;帮助开发者提高代码的可维护性、可重用性和可扩展性。 设计模式主…...

【Linux】软硬链接和动静态库

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…...

HarmonyOS入门 : 获取网络数据,并渲染到界面上

1. 环境搭建 开发HarmonyOS需要安装DevEco Studio&#xff0c;下载地址 : https://developer.huawei.com/consumer/cn/deveco-studio/ 2. 如何入门 入门HarmonyOS我们可以从一个实际的小例子入手&#xff0c;比如获取网络数据&#xff0c;并将其渲染到界面上。 本文就是基于…...

【贪心】【哈希】个人练习-Leetcode-1296. Divide Array in Sets of K Consecutive Numbers

题目链接&#xff1a;https://leetcode.cn/problems/divide-array-in-sets-of-k-consecutive-numbers/description/ 题目大意&#xff1a;给出一个数组nums[]和一个数k&#xff0c;求nums[]能否被分成若干个k个元素的连续的子列。 思路&#xff1a;比较简单&#xff0c;贪心就…...

【数据库实验一】数据库及数据库中表的建立实验

目录 实验1 学习RDBMS的使用和创建数据库 一、 实验目的 二、实验内容 三、实验环境 四、实验前准备 五、实验步骤 六、实验结果 七、评价分析及心得体会 实验2 定义表和数据库完整性 一、 实验目的 二、实验内容 三、实验环境 四、实验前准备 五、实验步骤 六…...

Web服务nginx基本实验

安装软件&#xff1a; 启动服务&#xff1a; 查看Nginx服务器的网络连接信息&#xff0c;监听的端口&#xff1a; 查看默认目录&#xff1a; 用Windows访问服务端192.168.234.111的nginx服务&#xff1a;&#xff08;防火墙没有放行nginx服务&#xff0c;访问不了&#xff09; …...

Ubuntu实现双击图标运行自己的应用软件

我们知道在Ubuntu上编写程序&#xff0c;最后编译得到的是一个可执行文件&#xff0c;大致如下 然后要运行的时候在终端里输入./hello即可 但是这样的话感觉很丑很不方便&#xff0c;下边描述一种可以类似Windows上那种双击运行的实现方式。 我们知道Ubuntu是有一些自带的程序…...

js id字符串转数组

将一个逗号分隔的字符串&#xff08;例如 "12,123,213,"&#xff09;转换为一个 JavaScript 数组&#xff0c;并去除多余的逗号&#xff0c;可以使用以下几种方法。这里我将展示几种常见的方式&#xff1a; 方法 1: 使用 split 和 filter 你可以使用 split 方法将字…...

《手写Spring渐进式源码实践》实践笔记(第十八章 JDBC功能整合)

文章目录 第十八章 JDBC功能整合背景技术背景JDBC JdbcTemplate关键特性 用法示例业务背景 目标设计实现代码结构类图实现步骤 测试事先准备属性配置文件测试用例测试结果&#xff1a; 总结 第十八章 JDBC功能整合 背景 技术背景 JDBC JDBC&#xff08;Java Database Conne…...

边缘计算在智能交通系统中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 边缘计算在智能交通系统中的应用 边缘计算在智能交通系统中的应用 边缘计算在智能交通系统中的应用 引言 边缘计算概述 定义与原…...

HTML5+css3(浮动,浮动的相关属性,float,解决浮动的塌陷问题,clear,overflow,给父亲盒子加高度,伪元素)

浮动的相关属性 以下使浮动的常用属性值&#xff1a; float&#xff1a; 设置浮动 以下属性&#xff1a; left : 设置左浮动 right : 设置右浮动 none &#xff1a;不浮动&#xff0c;默认值clear 清除浮动 清除前面兄弟元素浮动元素的响应 以下属性&#xff1a; left &…...

【C++ 滑动窗口】2134. 最少交换次数来组合所有的 1 II

本文涉及的基础知识点 C算法&#xff1a;滑动窗口及双指针总结 LeetCode2134. 最少交换次数来组合所有的 1 II 交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。 环形 数组是一个数组&#xff0c;可以认为 第一个 元素和 最后一个 元素 相邻 。 给你一个 二…...

使用 PyTorch 实现并测试 AlexNet 模型,并使用 TensorRT 进行推理加速

本篇文章详细介绍了如何使用 PyTorch 实现经典卷积神经网络 AlexNet,并利用 Fashion-MNIST 数据集进行训练与测试。在训练完成后,通过 TensorRT 进行推理加速,以提升模型的推理效率。 本文全部代码链接:全部代码下载 环境配置 为了保证代码在 GPU 环境下顺利运行,我们将…...

Python 数据可视化详解教程

Python 数据可视化详解教程 数据可视化是数据分析中不可或缺的一部分&#xff0c;它通过图形化的方式展示数据&#xff0c;帮助我们更直观地理解和分析数据。Python 作为一种强大的编程语言&#xff0c;拥有丰富的数据可视化库&#xff0c;如 Matplotlib、Seaborn、Plotly 和 …...

springboot集成opencv开源计算机视觉库

最近项目需要用到opencv&#xff0c;网上看到很多资料都是下载安装并且引入jar包与dll文件&#xff0c;感觉很麻烦&#xff0c;不是我想要的&#xff0c;于是花时间折腾了下&#xff0c;不需要任何安装与引入jar包与dll文件&#xff0c;简单方便&#xff0c;快速上手。 先说说…...

CCF ChinaOSC |「开源科学计算与系统建模openSCS专题分论坛」11月9日与您相约深圳

2024年11月9日至10日&#xff0c;以“湾区聚力 开源启智”为主题的2024年中国计算机学会中国开源大会&#xff08;CCF ChinaOSC&#xff09;将在深圳召开。大会将汇聚国内外学术界、顶尖科技企业、科研机构及开源社区的精英力量&#xff0c;共同探索人工智能技术和人类智慧的无…...

2024年11月8日上海帆软用户大会

2024年11月8日上海帆软用户大会 2024年11月8日&#xff0c;上海成功举办了帆软用户大会&#xff0c;主题为“数字聚力&#xff0c;绽放新机”。大会汇聚了众多行业专家和企业代表&#xff0c;共同探讨数字化转型和商业智能领域的最新趋势和实践。 大会亮点&#xff1a; 专家…...

信息泄露漏洞一文速通

文章目录 信息泄露漏洞一文速通敏感信息の概念敏感信息の分类企业敏感信息用户敏感信息站点敏感信息 如何挖掘信息泄露漏洞&#xff1f;信息泄露风险清单&#xff08;checklist&#xff09;未授权访问类文件与数据泄露开发与调试信息泄露公共配置文件泄露其他敏感信息泄露点 威…...

Android 启动时应用的安装解析过程《二》

上一篇内容说到InitAppsHelper这个类的initSystemApps函数&#xff0c;只说了一下几个重要参数的来源还没展开&#xff0c;这里继续&#xff0c;有兴趣的可以看链接: Android 启动时应用的安装解析过程《一》 一、系统应用的扫描安装 /*** Install apps from system dirs.*/Gu…...

智谱AI:ChatGLM强大的生成式语言模型

目录 智谱AI:ChatGLM强大的生成式语言模型 一、ChatGLM的定义与特点 二、ChatGLM的应用场景 三、举例说明 四、注意事项 智谱AI:ChatGLM强大的生成式语言模型 它通过对话的方式能够生成自然流畅的文本,这一特性使其在多个领域都有广泛的应用潜力,特别是在智能对话和智能…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...