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

《C++设计模式》策略模式

文章目录

  • 1、引言
    • 1.1 什么是策略模式
    • 1.2 策略模式的应用场景
    • 1.3 本文结构概览
  • 2、策略模式的基本概念
    • 2.1 定义与结构
    • 2.2 核心角色解析
      • 2.2.1 策略接口(Strategy)
      • 2.2.2 具体策略实现(ConcreteStrategy)
      • 2.2.3 上下文(Context)
  • 3、C++中的策略模式实现
    • 3.1 示例场景设定
    • 3.2 策略接口定义
    • 3.3 具体策略实现
      • 3.3.1 策略A实现:信用卡支付
      • 3.3.2 策略B实现:现金支付
    • 3.4 上下文类设计
    • 3.5 完整代码示例
  • 4、策略模式的优点与缺点
    • 4.1 优点
      • 4.1.1 算法自由切换
      • 4.1.2 开闭原则支持
      • 4.1.3 简化单元测试
    • 4.2 缺点
      • 4.2.1 策略类数量膨胀
      • 4.2.2 客户端需要了解策略接口
  • 5、策略模式的应用实例
    • 5.1 电商平台的促销策略
    • 5.2 游戏中的AI行为选择
    • 5.3 图像处理中的滤镜选择
  • 6、策略模式与其他设计模式的比较
    • 6.1 与状态模式的对比
    • 6.2 与模板方法模式的对比
    • 6.3 与装饰者模式的对比
  • 7、高级话题与最佳实践
    • 7.1 使用智能指针管理策略对象
    • 7.2 策略工厂模式简化策略创建
    • 7.3 线程安全考虑
  • 8、总结
    • 8.1 策略模式的核心价值
    • 8.2 何时使用策略模式
    • 8.3 后续学习资源推荐
  • 9、参考文献与进一步阅读
    • 9.1 相关书籍推荐

1、引言

1.1 什么是策略模式

策略模式(Strategy Pattern) 是一种行为型设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互换。策略模式使得算法可以独立于使用它的客户端而变化。策略模式让算法的变化 独立 于使用算法的客户。
在策略模式中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式,因为算法或行为是通过其上下文(Context)来选择的。
简单来说,策略模式就是定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式使得算法可独立于使用它的客户而变化,即算法本身和使用算法的客户端代码是解耦的。

1.2 策略模式的应用场景

策略模式在软件开发中有着广泛的应用场景,包括但不限于以下几种情况:
(1)多种算法的实现:当存在多种算法,而这些算法的实现又需要频繁地更换或扩展时,可以考虑使用策略模式。通过定义不同的策略类来实现不同的算法,客户端可以根据需要选择具体的策略。
(2)条件分支语句的替代:在程序中,如果存在大量的条件分支语句(如if-else或switch-case),并且这些条件分支语句的实现逻辑比较复杂或容易变化时,可以考虑使用策略模式来替代这些条件分支语句。通过定义不同的策略类来实现不同的分支逻辑,客户端可以根据条件选择具体的策略。
(3)算法与数据结构的分离:在某些情况下,算法和数据结构是紧密相关的,但有时候我们可能需要将算法与数据结构进行分离,以便能够独立地修改或扩展它们。这时,可以使用策略模式来将算法封装成独立的策略类,从而实现算法与数据结构的分离。
(4)可配置的行为:在某些系统中,某些行为可能需要根据配置或用户的选择来改变。这时,可以使用策略模式来定义不同的策略类,并根据配置或用户的选择来选择具体的策略。

1.3 本文结构概览

本文旨在详细介绍C++中的策略模式,包括其基本概念、实现方法、优缺点以及应用场景等方面。文章将分为以下几个部分:
引言:介绍策略模式的基本概念、应用场景以及本文的结构概览。
策略模式的基本概念:详细解释策略模式的定义、结构以及核心角色。
C++中的策略模式实现:通过具体的代码示例来展示如何在C++中实现策略模式。
策略模式的优缺点:分析策略模式的优点和缺点,以便更好地理解其适用场景和限制。
策略模式的应用实例:介绍一些实际项目中应用策略模式的例子,以便读者更好地理解其应用价值。
总结与展望:总结本文的主要内容,并对策略模式的发展和应用前景进行展望。
希望本文能够帮助读者深入理解C++中的策略模式,并能够在实际项目中灵活运用该模式来解决实际问题。

2、策略模式的基本概念

2.1 定义与结构

策略模式(Strategy Pattern),又称为政策模式(Policy),是一种对象行为型模式。其定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
从软件设计角度看,策略模式在一个任务中,将算法部分封装成独立的接口,和任务分离,以便可以动态选用不同算法。策略模式使得可以定义新的算法,而不引起任务本身的代码变动。这里的算法可以是数学上的算法,也可以是一个处理具体问题的方案。

2.2 核心角色解析

策略模式通常包含以下三个核心角色:

2.2.1 策略接口(Strategy)

定义:策略接口定义了一组算法或行为的公共接口,所有具体策略类都需要实现这个接口。这个接口的实现各不相同,每个实现对应一种具体的算法或行为。
作用:为所支持的算法声明了抽象方法,是所有策略类的父类。它可以是抽象类或具体类,也可以是接口。环境类通过策略接口中声明的方法在运行时调用具体策略类中实现的算法。

2.2.2 具体策略实现(ConcreteStrategy)

定义:具体策略类实现了策略接口中声明的算法。
作用:在运行时,具体策略类将覆盖在环境类中定义的策略接口对象,使用一种具体的算法实现某个业务功能。

2.2.3 上下文(Context)

定义:上下文是使用算法的角色,它在解决某个问题(即实现某个功能)时可以采用多种策略。
作用:
封装了具体策略的执行逻辑,提供给客户端使用的接口。
维持一个对策略接口的引用实例,用于定义所采用的策略。
可以在运行时动态地更换策略,从而改变算法的行为。上下文对象不需要了解算法的细节,只需调用策略接口即可。
通过以上三个角色的协同工作,策略模式实现了算法的灵活切换和扩展,提高了代码的可维护性和复用性。

3、C++中的策略模式实现

3.1 示例场景设定

为了演示C++中的策略模式,我们设定一个简单的支付系统场景。在这个系统中,用户可以选择不同的支付方式来完成支付,如信用卡支付、现金支付和支付宝支付。每种支付方式对应一个具体的策略,而支付系统则作为上下文类,根据用户的选择来执行相应的支付策略。

3.2 策略接口定义

首先,我们定义一个策略接口PaymentStrategy,它包含一个纯虚函数pay,用于执行支付操作。

#include <iostream>
#include <memory>// 策略接口
class PaymentStrategy {
public:virtual ~PaymentStrategy() = default;virtual void pay(double amount) const = 0;
};

3.3 具体策略实现

接下来,我们实现三个具体的支付策略:信用卡支付CreditCardPayment、现金支付CashPayment和支付宝支付AlipayPayment。

3.3.1 策略A实现:信用卡支付

// 信用卡支付策略
class CreditCardPayment : public PaymentStrategy {
public:void pay(double amount) const override {std::cout << "Paid " << amount << " using Credit Card." << std::endl;}
};

3.3.2 策略B实现:现金支付

// 现金支付策略
class CashPayment : public PaymentStrategy {
public:void pay(double amount) const override {std::cout << "Paid " << amount << " using Cash." << std::endl;}
};
(注:为了简洁,这里只展示了两个具体策略的实现,支付宝支付的实现方式类似,可以作为练习留给读者。)

3.4 上下文类设计

上下文类PaymentContext持有一个指向PaymentStrategy的指针(或智能指针),用于在运行时选择具体的支付策略。

// 上下文类
class PaymentContext {
private:std::unique_ptr<PaymentStrategy> strategy;public:PaymentContext(std::unique_ptr<PaymentStrategy> strategy): strategy(std::move(strategy)) {}void setStrategy(std::unique_ptr<PaymentStrategy> newStrategy) {strategy = std::move(newStrategy);}void pay(double amount) const {strategy->pay(amount);}
};

3.5 完整代码示例

下面是一个完整的代码示例,展示了如何在C++中使用策略模式来实现支付系统。

#include <iostream>
#include <memory>// 策略接口
class PaymentStrategy {
public:virtual ~PaymentStrategy() = default;virtual void pay(double amount) const = 0;
};// 信用卡支付策略
class CreditCardPayment : public PaymentStrategy {
public:void pay(double amount) const override {std::cout << "Paid " << amount << " using Credit Card." << std::endl;}
};// 现金支付策略
class CashPayment : public PaymentStrategy {
public:void pay(double amount) const override {std::cout << "Paid " << amount << " using Cash." << std::endl;}
};// 上下文类
class PaymentContext {
private:std::unique_ptr<PaymentStrategy> strategy;public:PaymentContext(std::unique_ptr<PaymentStrategy> strategy): strategy(std::move(strategy)) {}void setStrategy(std::unique_ptr<PaymentStrategy> newStrategy) {strategy = std::move(newStrategy);}void pay(double amount) const {strategy->pay(amount);}
};int main() {// 创建具体的支付策略对象auto creditCard = std::make_unique<CreditCardPayment>();auto cash = std::make_unique<CashPayment>();// 创建上下文对象,并设置初始的支付策略为信用卡支付PaymentContext context(std::move(creditCard));// 执行支付操作context.pay(100.0);  // 输出: Paid 100 using Credit Card.// 动态更改支付策略为现金支付context.setStrategy(std::move(cash));// 再次执行支付操作context.pay(200.0);  // 输出: Paid 200 using Cash.return 0;
}

在这个示例中,我们首先定义了策略接口PaymentStrategy,然后实现了两个具体的支付策略CreditCardPayment和CashPayment。接着,我们设计了上下文类PaymentContext,它持有一个指向PaymentStrategy的智能指针,用于在运行时选择具体的支付策略。最后,在main函数中,我们演示了如何创建具体的支付策略对象、设置上下文对象的支付策略,并执行支付操作。

4、策略模式的优点与缺点

4.1 优点

4.1.1 算法自由切换

策略模式使得算法可以独立于使用它的客户端而变化。这意味着客户端可以在运行时根据需要动态地选择不同的算法,而无需修改客户端的代码。这种灵活性有助于在不影响其他部分的情况下对系统进行扩展和修改。

4.1.2 开闭原则支持

策略模式遵循开闭原则,即对扩展开放,对修改关闭。通过增加新的策略类而不是修改已有的类来实现功能的扩展,这使得系统更加易于维护和扩展。

4.1.3 简化单元测试

由于策略模式将算法封装在独立的类中,因此可以针对每个策略类进行单独的单元测试。这有助于确保每个算法的正确性,并降低整体系统的测试复杂度。

4.2 缺点

4.2.1 策略类数量膨胀

当系统中存在大量的算法或行为时,使用策略模式可能会导致策略类的数量急剧增加。这会增加系统的复杂性和维护成本,因为需要管理大量的类和接口。

4.2.2 客户端需要了解策略接口

在使用策略模式时,客户端需要了解并选择合适的策略类。这要求客户端具有一定的了解和判断能力,以便在运行时选择最合适的算法或行为。如果客户端对策略接口的了解不足,可能会导致选择错误的策略类,从而影响系统的正确性和性能。

5、策略模式的应用实例

5.1 电商平台的促销策略

在电商平台中,促销策略是吸引用户、提高转化率的重要手段。传统的促销策略往往依赖于经验和直觉,缺乏数据支撑和精准度。随着大数据和人工智能技术的快速发展,电商促销策略也迎来了新的变革。通过策略模式,电商平台可以根据用户行为、商品属性、市场趋势等数据,构建更精准、更有效的促销策略。例如,根据用户的浏览历史、购买记录等信息,推荐个性化的商品和促销活动;或者通过分析用户对不同促销活动的响应情况,优化促销活动的时间、力度和内容。

5.2 游戏中的AI行为选择

在策略游戏中,AI的行为选择对于游戏的平衡性和趣味性至关重要。通过策略模式,游戏开发者可以为AI设计多种不同的行为策略,并在游戏运行时根据战局情况动态选择最合适的策略。例如,在战斗场景中,AI可以根据敌人的数量和类型、自身的资源和能力等因素,选择进攻、防御或撤退等不同的行为策略。这种灵活性使得游戏更加具有挑战性和趣味性。

5.3 图像处理中的滤镜选择

在图像处理软件中,滤镜是常用的功能之一。通过策略模式,可以将不同的滤镜算法封装成独立的策略类,并提供统一的接口供用户选择。这样,用户可以根据需要选择不同的滤镜来处理图像,例如模糊、锐化、颜色调整等。这种设计方式使得图像处理软件更加灵活和易于扩展,同时也提高了用户的操作体验和满意度。
综上所述,策略模式是一种强大的设计模式,它允许在运行时根据不同的策略选择不同的算法或行为。虽然它也有一些缺点,但在适当的场景下使用策略模式可以带来显著的优点和好处。

6、策略模式与其他设计模式的比较

6.1 与状态模式的对比

结构差异:
策略模式在结构上相对简单,通常包含一个环境类(Context),它持有一个策略接口(Strategy)的引用,以及多个实现了该接口的具体策略类(ConcreteStrategy)。
状态模式则更为复杂,它包含了一系列的状态对象(State),这些状态对象可以持有自己的数据,并定义了在不同状态下对象应该采取的行为。状态模式中的环境类(Context)通常持有一个当前状态对象的引用,并委托给该状态对象处理请求。
行为变化:
策略模式关注的是算法或行为的变化,这些算法或行为是独立且可替换的。客户端可以在运行时选择不同的策略对象,以实现不同的行为。
状态模式则关注的是对象在不同状态下的行为变化,以及状态之间的切换。它允许对象在内部状态改变时自动改变其行为。
使用场景:
策略模式适用于系统中存在多种算法或行为,且这些算法或行为可以独立变化的情况。
状态模式适用于对象的行为随其内部状态改变而改变,且这些状态之间的切换逻辑较为复杂的情况。

6.2 与模板方法模式的对比

结构差异:
策略模式包含环境类、策略接口和具体策略实现类。
模板方法模式则包含一个抽象类(AbstractClass),该类中定义了一个算法的骨架,并包含了一些抽象方法或钩子方法(Hook),这些方法的具体实现由子类提供。
关注点:
策略模式关注的是算法或行为的替换和选择,它允许客户端在运行时动态地选择不同的策略对象。
模板方法模式关注的是算法的骨架和具体步骤的延迟实现。它提供了一个算法的总体结构,但允许子类根据需要重写或扩展某些步骤。
使用场景:
策略模式适用于需要动态选择不同算法或行为的情况。
模板方法模式适用于算法或行为的基本结构固定,但具体实现因子类而异的情况。

6.3 与装饰者模式的对比

结构差异:
策略模式和装饰者模式在结构上有所不同。策略模式主要包含环境类、策略接口和具体策略实现类。
装饰者模式则包含一个基本的组件类(Component)和多个装饰者类(Decorator),每个装饰者类都持有一个组件的引用,并可以在该组件的基础上添加额外的行为或功能。
关注点:
策略模式关注的是算法或行为的替换和选择。
装饰者模式关注的是在不改变类结构的情况下,动态地为对象添加额外的功能或行为。
使用场景:
策略模式适用于需要动态选择不同算法或行为的情况。
装饰者模式适用于需要在不修改原有类代码的情况下,为对象添加新的功能或行为的情况。

7、高级话题与最佳实践

7.1 使用智能指针管理策略对象

在C++等语言中,使用智能指针(如std::shared_ptr或std::unique_ptr)来管理策略对象可以自动处理内存分配和释放,避免内存泄漏和悬挂指针等问题。智能指针通过引用计数或其他机制来确保对象在不再被需要时自动销毁。
使用智能指针管理策略对象时,需要注意以下几点:
确保策略对象被正确地创建和初始化。
避免在多个线程之间共享同一个智能指针,除非该智能指针是线程安全的。
在不再需要策略对象时,确保它能够被正确地销毁和释放。

7.2 策略工厂模式简化策略创建

为了简化策略对象的创建过程,可以使用工厂模式(如简单工厂、工厂方法或抽象工厂)来封装策略对象的创建逻辑。这样,客户端只需要与工厂接口交互,而无需了解具体策略类的实现细节。
使用策略工厂模式时,需要注意以下几点:
工厂类应该提供一个统一的接口来创建不同类型的策略对象。
工厂类应该能够处理策略对象的创建和初始化过程中的任何异常或错误。
客户端应该通过工厂接口来获取策略对象,而不是直接实例化具体策略类。

7.3 线程安全考虑

在多线程环境中使用策略模式时,需要考虑线程安全问题。如果策略对象的状态在多个线程之间共享,那么需要采取适当的同步机制来确保线程安全。
以下是一些常见的线程安全考虑:
使用线程安全的智能指针来管理策略对象。
在策略对象的方法中添加适当的同步机制(如互斥锁或读写锁)。
避免在多个线程之间共享可变的状态信息,除非使用了适当的同步机制。
在设计策略模式时,尽量将状态信息封装在策略对象内部,并通过不可变对象或线程安全的集合来传递状态信息。
总之,在使用策略模式时,需要根据具体的应用场景和需求来选择合适的设计和实现方式,并关注线程安全、内存管理等高级话题和最佳实践。

8、总结

8.1 策略模式的核心价值

策略模式的核心价值在于提供了一种灵活且可扩展的方式来处理算法或行为的变化。它将算法或行为封装成独立的策略类,使得这些策略可以互换,而客户端代码则可以根据需要动态地选择不同的策略。这种设计使得系统更加灵活,易于维护和扩展。策略模式的核心价值主要体现在以下几个方面:
提高了系统的灵活性和可扩展性:通过封装不同的算法或行为,策略模式使得系统可以轻松地添加新的策略,而无需修改现有的客户端代码。
简化了客户端代码:客户端代码只需要与抽象策略类进行交互,而无需关心具体的策略实现,从而简化了客户端代码。
实现了算法或行为的可重用性:不同的策略类可以共享相同的接口或抽象类,这使得算法或行为可以在不同的上下文中重用。
增强了系统的可维护性:由于策略模式将算法或行为封装在独立的类中,因此当某个算法或行为需要修改时,只需要修改相应的策略类即可,而不会影响到其他部分的代码。

8.2 何时使用策略模式

策略模式适用于以下场景:
算法或行为有多种变体:当系统需要实现多种算法或行为,并且这些算法或行为之间可以互换时,可以使用策略模式。
避免使用多重条件语句:如果系统中的算法或行为选择依赖于多个条件语句,这会导致代码难以理解和维护。此时,可以使用策略模式将不同的算法或行为封装成独立的类,从而消除多重条件语句。
需要动态选择算法或行为:当系统中的算法或行为需要在运行时动态选择时,可以使用策略模式。客户端代码可以根据需要选择不同的策略类,从而实现动态的行为选择。
需要封装复杂的算法或行为:如果系统中的某个算法或行为非常复杂,需要将其封装起来以便更好地理解和维护,那么可以使用策略模式。

8.3 后续学习资源推荐

为了深入学习策略模式及其在实际项目中的应用,以下是一些推荐的学习资源:
《设计模式:可复用面向对象软件的基础》(Erich Gamma等著):这本书是设计模式领域的经典之作,详细介绍了包括策略模式在内的多种设计模式。
《重构:改善既有代码的设计》(Martin Fowler著):这本书提供了许多实用的重构技巧,其中也包括对策略模式的讨论和应用。

9、参考文献与进一步阅读

9.1 相关书籍推荐

《设计模式:可复用面向对象软件的基础》:这本书是设计模式领域的权威之作,详细阐述了各种设计模式的概念、原理和应用场景。对于想要深入理解策略模式及其在其他设计模式中的关系的读者来说,这本书是不可或缺的。
《重构:改善既有代码的设计》:这本书提供了许多实用的重构技巧和方法,其中也包括对策略模式的讨论和应用。通过这本书,你可以学习如何在现有代码中应用策略模式来改善代码的可读性和可维护性。

相关文章:

《C++设计模式》策略模式

文章目录 1、引言1.1 什么是策略模式1.2 策略模式的应用场景1.3 本文结构概览 2、策略模式的基本概念2.1 定义与结构2.2 核心角色解析2.2.1 策略接口&#xff08;Strategy&#xff09;2.2.2 具体策略实现&#xff08;ConcreteStrategy&#xff09;2.2.3 上下文&#xff08;Cont…...

JavaScript学习记录6

第一节 算数运算符 1. 概述 JavaScript 共提供10个算术运算符&#xff0c;用来完成基本的算术运算。 加法运算符x y减法运算符 x - y乘法运算符 x * y除法运算符x / y指数运算符x ** y余数运算符x % y自增运算符x 、x自减运算符--x 、x--数值运算符 x负数值运算符-x 减法、…...

如何在没有 iCloud 的情况下将数据从 iPhone 传输到 iPhone

概括 您可能会遇到将数据从 iPhone 转移到 iPhone 的情况&#xff0c;尤其是当您获得新的 iPhone 15/14 时&#xff0c;您会很兴奋并希望将数据转移到它。 使用iCloud最终可以做到这一点&#xff0c;但它的缺点也不容忽视&#xff0c;阻碍了你选择它。例如&#xff0c;您需要…...

Doris安装部署

Doris 概述 Apache Doris由百度大数据部研发&#xff08;之前叫百度 Palo&#xff0c;2018年贡献到 Apache 社区后&#xff0c;更名为 Doris &#xff09;&#xff0c;在百度内部&#xff0c;有超过200个产品线在使用&#xff0c;部署机器超过1000台&#xff0c;单一业务最大可…...

[服务器][教程]Ubuntu24.04 Server开机自动挂载硬盘教程

1. 查看硬盘ID ls -l /dev/disk/by-uuid可以看到对应的UUID所对应的分区 2. 创建挂载文件夹 创建好文件夹即可 3. 修改配置文件 sudo vim /etc/fstab把对应的UUID和创建的挂载目录对应即可 其中# Personal mount points下面的是自己新添加的 &#xff1a;分区定位&#xff…...

io多路复用, select, poll, epoll

系列文章目录 异步I/O操作函数aio_xxx函数 https://blog.csdn.net/surfaceyan/article/details/134710393 文章目录 系列文章目录前言一、5种IO模型二、IO多路复用APIselectpollepoll 三、两种高效的事件处理模式Reactor模式Proactor模式模拟 Proactor 模式基于事件驱动的非阻…...

k8s-1.28.2 部署prometheus

一、prometheus helm仓库 ## 网站地址 # https://artifacthub.io/## prometheus 地址 # https://artifacthub.io/packages/helm/prometheus-community/prometheus. # helm repo add prometheus-community https://prometheus-community.github.io/helm-charts # helm repo …...

记录第一次跑YOLOV8做目标检测

今天是24年的最后一天&#xff0c;终于要向新世界开始破门了&#xff0c;开始深度学习&#xff0c;YOLO来敲门~ 最近做了一些皮肤检测的功能&#xff0c;在传统的处理中经历了反复挣扎&#xff0c;终于要上YOLO了。听过、看过&#xff0c;不如上手体会过~ 1、YOLO是什么&#x…...

使用Python爬取BOSS直聘职位数据并保存到Excel

使用Python爬取BOSS直聘职位数据并保存到Excel 在数据分析和挖掘中&#xff0c;爬取招聘网站数据是一项常见的任务。本文将详细介绍如何使用Python爬取BOSS直聘上与“测试工程师”相关的职位数据&#xff0c;并将其保存到Excel文件中。通过逐步分解代码和添加详细注释&#xf…...

node.js之---集群(Cluster)模块

为什么会有集群&#xff08;Cluster&#xff09;模块&#xff1f; 集群&#xff08;Cluster&#xff09;模块的作用 如何使用集群&#xff08;Cluster&#xff09;模块&#xff1f; 为什么会有集群&#xff08;Cluster&#xff09;模块 Node.js 是基于 单线程事件驱动 模型的…...

SSM-Spring-IOC/DI对应的配置开发

目录 一、IOC 控制反转 1.什么是控制反转呢 2. Spring和IOC之间的关系是什么呢? 3.IOC容器的作用以及内部存放的是什么? 4.当IOC容器中创建好service和dao对象后&#xff0c;程序能正确执行么? 5.Spring 容器管理什么内容&#xff1f; 6.如何将需要管理的对象交给 …...

一文大白话讲清楚CSS元素的水平居中和垂直居中

文章目录 一文大白话讲清楚CSS元素的水平居中和垂直居中1.已知元素宽高的居中方案1.1 利用定位margin:auto1.2 利用定位margin负值1.3 table布局 2.未知元素宽高的居中方案2.1利用定位transform2.2 flex弹性布局2.3 grid网格布局 3. 内联元素的居中布局 一文大白话讲清楚CSS元素…...

航顺芯片推出HK32A040方案,赋能汽车矩阵大灯安全与智能化升级

汽车安全行驶对整车照明系统的要求正在向智能化方向发展。车灯位于汽车两侧&#xff0c;前期有各种各样的实现包括氙气灯、LED灯等等光源技术。矩阵大灯对汽车照明系统朝着安全性和智能化兼具的方向发展起到了重要推动作用。矩阵大灯可以精细控制到每一个小灯珠&#xff0c;从而…...

智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之12 方案再探:特定于领域的模板 之2 首次尝试和遗留问题解决

本文提要 现在就剩下“体”本身的 约定了--这必然是 自律自省的&#xff0c;或者称为“戒律” --即“体”的自我训导discipline。完整表述为&#xff1a; 严格双相的庄严“相” (<head>侧&#xff09;&#xff0c;完全双性的本质“性”&#xff08;<boot>侧&…...

redis zset底层实现

1.Redis zset底层实现 转载自&#xff1a;https://marticles.github.io/2019/03/19/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Redis-Zset%E5%8E%9F%E7%90%86/ zset底层是压缩列表 跳表实现的。 跳表里面又由字典hash表 跳表实现。 什么时候用压缩列表&#xff1f;什么时候用…...

go.Bar如何让hovertext显示为legend

在 Plotly 的 go.Bar 图中&#xff0c;如果你想让鼠标悬停时 (hover) 显示的文本 (hovertext) 与图例 (legend) 一致&#xff0c;可以通过 hovertemplate 来控制悬停时的显示内容。 实现方法 hovertemplate 是一种自定义工具&#xff0c;允许你完全控制悬停时的文本显示格式。…...

【Vue】分享一个快速入门的前端框架以及如何搭建

先上效果图: 登录 菜单: 下载地址: 链接&#xff1a;https://pan.baidu.com/s/1m-ZlBARWU6_2n8jZil_RAQ 提取码&#xff1a;ui20 … 主要是可以自定义设置token,更改后端请求地址较为方便。 应用设置: 登录与token设置: 在这里设置不用登录,可以请求的接口: request.js i…...

Flink源码解析之:如何根据JobGraph生成ExecutionGraph

Flink源码解析之&#xff1a;如何根据JobGraph生成ExecutionGraph 在上一篇Flink源码解析中&#xff0c;我们介绍了Flink如何根据StreamGraph生成JobGraph的流程&#xff0c;并着重分析了其算子链的合并过程和JobGraph的构造流程。 对于StreamGraph和JobGraph的生成来说&…...

UE(虚幻)学习(三) UnrealSharp插件中调用非托管DLL

上一篇文章中我使用UnrealSharp成功使用了我的一个C#控制台程序中的网络模块&#xff0c;这个程序是基于KCP网络了&#xff0c;其中调用了Cmake 编译的一个C的DLL&#xff0c;在虚幻中DLL需要放在Binaries目录中才可以。Unity中只要放在任意Plugins目录中就可以。 但是Binaries…...

leetcode 3219. 切蛋糕的最小总开销 II

题目&#xff1a;3219. 切蛋糕的最小总开销 II - 力扣&#xff08;LeetCode&#xff09; 排序贪心。 开销越大的越早切。 注意m或n为1的情况。 class Solution { public:long long minimumCost(int m, int n, vector<int>& horizontalCut, vector<int>&…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

DeepSeek越强,Kimi越慌?

被DeepSeek吊打的Kimi&#xff0c;还有多少人在用&#xff1f; 去年&#xff0c;月之暗面创始人杨植麟别提有多风光了。90后清华学霸&#xff0c;国产大模型六小虎之一&#xff0c;手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水&#xff0c;单月光是投流就花费2个亿。 疯…...

轻量级Docker管理工具Docker Switchboard

简介 什么是 Docker Switchboard &#xff1f; Docker Switchboard 是一个轻量级的 Web 应用程序&#xff0c;用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器&#xff0c;使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...