探索发布-订阅模式的深度奥秘-实现高效、解耦的系统通信

在这里插入图片描述
​🌈 个人主页:danci_
🔥 系列专栏:《设计模式》
💪🏻 制定明确可量化的目标,坚持默默的做事。
🚀 转载自:探索设计模式的魅力:探索发布-订阅模式的深度奥秘-实现高效、解耦的系统通信


探索发布-订阅模式的深度奥秘:实现高效、解耦的系统通信

文章目录

  • 一、案例场景🔍
    • 1.1 经典的运用场景
    • 1.2 一坨坨代码实现😻
    • 1.3 痛点
  • 二、解决方案🚀
    • 2.1 定义
    • 2.2 案例分析🧐
    • 2.3 模式结构图及说明
    • 2.4 使用模式重构示例
    • 2.5 重构后解决的问题👍

一、案例场景🔍

在这里插入图片描述

1.1 经典的运用场景

    发布-订阅模式在软件开发中拥有广泛的应用,它适用于多种场景,帮助开发者构建灵活、可扩展和松耦合的系统。以下是一些经典的应用场景及其在实际项目中的应用价值:👇

  1. 实时消息系统:
    在聊天应用、社交媒体平台或实时数据流处理中,发布-订阅模式允许用户发送消息到一个中央通道,而其他用户可以根据兴趣订阅这些通道以接收实时更新。这降低了发送者和接收者之间的直接依赖,支持高并发和实时通信。
  2. 事件驱动架构:
    在微服务或分布式系统中,服务之间通过事件进行通信。一个服务发布事件(如订单创建、用户注册等),而其他服务订阅这些事件并作出响应。这种异步通信方式提高了系统的响应性和可扩展性。
  3. 状态更新通知:
    在用户界面或后台管理中,当某个状态发生变化时(如数据库记录更新),发布-订阅模式可以确保相关组件或用户得到通知。这有助于实现实时反馈和动态更新。
  4. 日志和监控:
    系统日志和监控工具经常采用发布-订阅模式来收集、聚合和分发日志事件。发布者将日志事件发送到中央收集点,而订阅者可以是各种分析工具或警报系统。
  5. 物联网(IoT):
    在物联网应用中,设备产生的大量数据需要被实时处理和分发。发布-订阅模式允许设备将数据发布到消息代理,而各种服务和应用程序可以订阅这些数据流以进行实时分析或响应。
  6. 股票交易和金融市场:
    在金融应用中,实时数据流(如股票价格变动)对交易者至关重要。发布-订阅模式确保交易者能够订阅他们感兴趣的金融工具,并在价格变动时立即收到通知。

    下面我们来实现实时消息系统场景 📄✏️。

1.2 一坨坨代码实现😻

在这里插入图片描述

    要使用Java实现第一个场景(实时消息系统)而不直接使用发布-订阅设计模式,我们可以使用基础的Java并发和集合类来模拟这个系统。下面是一个简单的示例,展示了如何实现一个简易的实时聊天系统。

import java.util.ArrayList;  
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
import java.util.concurrent.CopyOnWriteArrayList;  public class SimpleChatSystem {  // 存储所有用户的聊天室  private static final Map<String, List<ChatListener>> chatRooms = new HashMap<>();  // 用于在控制台模拟用户发送消息  public static void main(String[] args) {  // 创建两个用户  ChatListener alice = new ChatListener("Alice");  ChatListener bob = new ChatListener("Bob");  // 将用户添加到同一个聊天室  String chatRoomName = "General";  addToChatRoom(chatRoomName, alice);  addToChatRoom(chatRoomName, bob);  // 模拟Alice发送消息  sendMessage(chatRoomName, "Alice: Hello, Bob!");  // 模拟Bob发送消息  sendMessage(chatRoomName, "Bob: Hi, Alice! How are you?");  }  // 将用户添加到聊天室  public static void addToChatRoom(String chatRoomName, ChatListener listener) {  chatRooms.computeIfAbsent(chatRoomName, k -> new CopyOnWriteArrayList<>()).add(listener);  }  // 从聊天室移除用户  public static void removeFromChatRoom(String chatRoomName, ChatListener listener) {  chatRooms.getOrDefault(chatRoomName, new ArrayList<>()).remove(listener);  }  // 发送消息到聊天室  public static void sendMessage(String chatRoomName, String message) {  List<ChatListener> listeners = chatRooms.get(chatRoomName);  if (listeners != null) {  for (ChatListener listener : listeners) {  listener.receiveMessage(message);  }  }  }  // 简单的聊天监听器,用于接收消息并打印到控制台  public static class ChatListener implements Runnable {  private final String name;  public ChatListener(String name) {  this.name = name;  }  public void receiveMessage(String message) {  System.out.println(name + " received: " + message);  }  @Override  public void run() {  // 这个run方法没有实际用途,只是为了让ChatListener实现Runnable接口  // 在实际应用中,ChatListener可能会是一个复杂的类,包含网络连接、消息处理等逻辑  }  }  
}

    在这个示例中,我们没有使用任何设计模式,而是直接使用了Java的基础类。我们创建了一个SimpleChatSystem类,它包含了一个静态的chatRooms映射,用于存储聊天室和其中的用户(ChatListener实例)。ChatListener是一个简单的接口,它有一个receiveMessage方法,用于接收并处理消息。
    在main方法中,我们创建了两个用户(Alice和Bob),并将它们添加到同一个聊天室。然后,我们模拟Alice和Bob发送消息到聊天室,所有在聊天室中的用户都会接收到这些消息,并将它们打印到控制台。

    注:上述实现只是个示例。在实际应用中,你可能需要考虑更多的因素,如网络编程、并发控制、错误处理、用户身份验证等。此外,如果你打算构建一个大规模的实时消息系统,使用专业的消息队列中间件(如RabbitMQKafka等)可能是一个更好的选择。

问题描述:
用java实现第一个场景,要求不使用设计模式、编码逻辑思路清晰

问题描述:
上述实现是否有优点?

    上述实现确实有一些优点,但也存在一些局限性。以下是对其优点的分析:👇

  1. 简单性:
    ✨ 这个实现非常直观和简单,易于理解和实现。它使用基础的Java类和并发控制来模拟实时消息系统,不需要掌握复杂的设计模式或框架。
  2. 演示目的:
    ✨ 作为一个示例,它很好地演示了如何使用Java的集合和并发特性来构建一个简单的实时通信系统。这对于初学者理解基本概念很有帮助。
  3. 静态模拟:
    ✨ 虽然它只在控制台中模拟用户之间的通信,但它可以作为一个起点,用于构建更复杂的系统。例如,可以将 ChatListener 类扩展为包含网络连接、GUI界面或与其他服务集成的功能。
  4. 无额外依赖:
    ✨ 该实现不依赖于任何外部库或框架,这意味着它可以在任何标准的Java环境中运行,无需担心依赖管理或版本兼容性问题。

    这个简单实现也有一些局限性,比如缺乏真正的异步通信、可扩展性限制、没有错误处理等。在实际项目中,通常会使用更复杂、更健壮的解决方案来处理这些问题。

1.3 痛点

在这里插入图片描述

    然而,没有复杂的设计下上述实现确实存在一些缺点,尤其是在面对更复杂、大规模或生产级别的实时消息系统需求时。以下是对其缺点的分析:👇

  1. 缺乏真正的异步通信:
    ✨ 虽然示例中的 ChatListener 可以接收消息,但整个系统并不是真正异步的。在真实世界的实时消息系统中,消息通常是通过异步方式发送和接收的,以提高响应性和吞吐量。

  2. 可扩展性限制:
    ✨ 由于使用了静态的映射来存储聊天室和用户,这个实现在处理大量用户或聊天室时可能会遇到性能瓶颈。此外,它也没有提供动态添加或删除聊天室的功能。

  3. 没有错误处理:
    ✨ 示例代码中没有包含任何错误处理逻辑。在实际应用中,网络中断、用户断开连接、消息格式错误等情况都需要妥善处理。

  4. 用户界面和交互性有限:
    ✨ 该实现仅在控制台打印接收到的消息,缺乏一个真正的用户界面或与其他服务的集成。这限制了其在现实世界应用中的实用性。

  5. 线程安全性问题:
    ✨ 虽然使用了 CopyOnWriteArrayList 来提供一定程度的线程安全,但在更复杂的多线程环境中,这可能不足以保证系统的稳定性和数据的一致性。例如,当同时添加和删除用户时,可能会出现竞态条件。

  6. 单一的消息传递方式:
    ✨ 示例中只有一种简单的消息传递方式,即广播到整个聊天室。在实际应用中,可能需要更复杂的消息路由和传递策略,如点对点消息、组播、主题订阅等。

  7. 缺乏持久化:
    ✨ 消息在发送后被立即消费,没有持久化机制来存储历史消息或支持离线消息传递。

  8. 缺乏认证和授权:
    ✨ 示例中没有实现用户认证和授权机制,这在任何需要安全性的应用中都是必需的。

    违反的设计原则(问题)下面逐一分析:👇

  1. 单一职责原则(SRP):
    SimpleChatSystem 类负责了多个职责,包括管理聊天室、添加/移除用户以及发送消息。这可能导致类变得难以维护和扩展。更好的做法是将这些职责拆分到不同的类中,例如,可以有一个专门的 ChatRoomManagerd 类来管理聊天室和用户,以及一个 MessageSender 类来负责发送消息。

  2. 开闭原则(OCP):
    ✨ 当前的实现不够灵活,无法在不修改现有代码的情况下添加新的功能或行为。例如,如果想要添加新的聊天室类型或消息传递方式,可能需要修改 SimpleChatSystem 类的代码。这违背了开闭原则,即软件实体应该对扩展开放,对修改关闭。

  3. 里氏替换原则(LSP):
    ✨ 虽然在这个简单的示例中没有明显的违反里氏替换原则的情况,但如果 ChatListener 接口被扩展或修改,可能会导致子类无法正确替换父类或接口的问题。这通常发生在当子类没有遵守父类的约定或行为时。

  4. 接口隔离原则(ISP):
    ChatListener 接口可能违反了接口隔离原则,因为它可能包含了不需要的方法(在这个简单示例中只有一个方法,但在更复杂的情况下可能会有更多)。如果接口过于庞大或包含不相关的方法,那么实现这个接口的类可能会被迫实现它们不需要的方法。

  5. 依赖倒置原则(DIP):
    ✨ 当前的实现中,高层模块(如SimpleChatSystem)直接依赖于低层模块(如ChatListener),这可能导致代码的耦合度过高。更好的做法是使用抽象(如接口或抽象类)来定义依赖关系,这样高层模块就可以依赖于抽象而不是具体的实现。

  6. 迪米特法则(LoD)或最少知识原则:
    ✨ 在这个实现中,SimpleChatSystem 类直接访问和操作了ChatListener 实例的内部状态(通过调用 receiveMessage 方法)。这违反了迪米特法则,即一个对象应该对其他对象保持最少的了解。更好的做法是通过定义清晰的接口和委托关系来减少类之间的直接依赖。

    注:设计原则是为了指导软件设计而提出的,旨在提高代码的可维护性、可扩展性和可重用性。在实际项目中,根据具体的需求和上下文,可能需要权衡这些原则的应用。不过,在构建更大规模或更复杂的系统时,遵循这些原则通常是有益的。

二、解决方案🚀

2.1 定义

发布订阅模式:一种消息传递模型,发送者不直接将消息发送给接收者,而是发送到中间层。

    接收者可以订阅这些消息,并在消息发布时接收到通知。这种模式的核心目的是实现发布者与订阅者之间的解耦,允许它们独立地扩展和修改,同时提供一种灵活的消息通信机制。通过发布订阅模式,系统可以更加灵活、可扩展和可维护。

2.2 案例分析🧐

在这里插入图片描述

2.3 模式结构图及说明

在这里插入图片描述

  • 发布者(Publisher):
    它是消息或者说主题的生产者,负责产生并发布消息到发布订阅管理器。发布者不需要知道或关心消息会被哪些订阅者接收,它只需要关注消息的发布。
  • 订阅者(Subscriber)
    它是订阅消息或主题的消费者,负责从发布订阅管理器接收并处理感兴趣的消息。订阅者需要提前向发布订阅管理器订阅自己感兴趣的主题,当发布者发布相关主题的消息时,发布订阅管理器会将消息推送给所有订阅了该主题的订阅者。
  • 发布订阅管理器:
    它是整个发布订阅模式的核心,负责接收并存储发布者发布的消息,同时管理订阅者的订阅信息。当发布者发布消息时,发布订阅管理器会根据订阅信息将消息推送给相应的订阅者。发布订阅管理器实现了发布者与订阅者之间的解耦,使得它们可以独立地扩展和修改。

    发布订阅模式的功能是实现消息的发布与订阅,提供了一种灵活的消息通信机制,使得消息的发送者和接收者可以解耦,提高了系统的灵活性和可扩展性。同时,发布订阅模式还支持一对多、多对多的消息通信,可以满足复杂场景下的消息通信需求。

2.4 使用模式重构示例

    为了解决上述实现中的缺点,并采用发布订阅模式重构实时消息系统,我们需要对原有的代码结构进行调整。以下是一个简化的重构示例:👇

  1. 首先,定义消息发布的接口和消息订阅的接口:
// 定义消息类型  
public class Message {  private String sender;  private String content;  // 构造方法、getters和setters略...  
}  // 消息发布接口  
public interface MessagePublisher {  void publish(Message message);  
}  // 消息订阅接口  
public interface MessageSubscriber {  void onMessage(Message message);  
}  // 消息订阅管理器,管理订阅者和消息的分发  
public class MessageSubscriptionManager implements MessagePublisher {  private List<MessageSubscriber> subscribers = new CopyOnWriteArrayList<>();  @Override  public void publish(Message message) {  for (MessageSubscriber subscriber : subscribers) {  subscriber.onMessage(message);  }  }  public void subscribe(MessageSubscriber subscriber) {  subscribers.add(subscriber);  }  public void unsubscribe(MessageSubscriber subscriber) {  subscribers.remove(subscriber);  }  
}
  1. 接下来,我们定义ChatRoom类,它将包含 MessageSubscriptionManager 实例来管理订阅和消息发布:
public class ChatRoom {  private String name;  private MessageSubscriptionManager subscriptionManager = new MessageSubscriptionManager();  public ChatRoom(String name) {  this.name = name;  }  public void sendMessage(String sender, String content) {  Message message = new Message(sender, content);  subscriptionManager.publish(message);  }  public void subscribe(MessageSubscriber subscriber) {  subscriptionManager.subscribe(subscriber);  }  public void unsubscribe(MessageSubscriber subscriber) {  subscriptionManager.unsubscribe(subscriber);  }  
}
  1. 最后,实现一个简单的 MessageSubscriber 示例,它可以接收并处理来自 ChatRoom 的消息:
public class ChatUser implements MessageSubscriber {  private String username;  public ChatUser(String username) {  this.username = username;  }  @Override  public void onMessage(Message message) {  System.out.println(username + " received message from " + message.getSender() + ": " + message.getContent());  }  // getters和setters略...  
}
  1. 现在,创建 ChatRoomChatUser 的实例,并将用户订阅到聊天室中,以接收实时消息:
public class RealTimeMessagingSystem {  public static void main(String[] args) {  ChatRoom chatRoom = new ChatRoom("General");  ChatUser user1 = new ChatUser("Alice");  ChatUser user2 = new ChatUser("Bob");  chatRoom.subscribe(user1);  chatRoom.subscribe(user2);  // 发送消息到聊天室  chatRoom.sendMessage("Server", "Hello, everyone!");  // ... 可以添加更多逻辑,比如用户之间的交互,或用户发送消息等。  // 当某个用户需要离开时,取消订阅  chatRoom.unsubscribe(user1);  }  
}

    <这个重构示例遵循了发布订阅模式,允许用户订阅聊天室的消息,并通过聊天室发送消息给所有订阅者。此外,通过 MessageSubscriptionManager 来管理订阅者和消息的分发,使得系统更加解耦、灵活,并支持多个用户之间的实时交互。这种模式使得系统易于扩展,能够适应不同数量和类型的订阅者和消息类型。

2.5 重构后解决的问题👍

在这里插入图片描述

    优点
    上述使用发布订阅模式的实现解决了以下已知缺点:👇

  1. 解耦:
    ✨ 在原始的实现中,发送者和接收者之间可能存在直接的依赖关系,这限制了系统的灵活性和可维护性。通过使用发布订阅模式,我们引入了中间层(MessageSubscriptionManager),使得发送者(发布者)和接收者(订阅者)之间解耦。这意味着发送者不需要知道或关心消息被哪些接收者处理,同样,接收者也不需要知道消息来自哪个发送者。

  2. 可扩展性:
    ✨ 发布订阅模式允许系统更容易地扩展。无论是增加新的订阅者还是处理更多的消息类型,都不需要对现有代码进行大量修改。在重构后的代码中,添加新的订阅者只需要调用 subscribe 方法,而移除订阅者则调用 unsubscribe 方法。

  3. 实时性与异步处理:
    ✨ 发布订阅模式天然支持异步消息传递。在重构后的系统中,消息的发送是异步的,发送者不需要等待接收者的响应。这提高了系统的响应性和吞吐量,使得它能够更好地处理实时消息。

  4. 容错性与可靠性:
    ✨ 虽然上述示例代码没有直接展示容错性机制,但发布订阅模式为实现容错性和可靠性提供了基础。例如,中间层可以设计为支持消息的持久化存储,以便在订阅者暂时不可用时保留消息。此外,通过监控和重试机制,可以确保消息最终被传递给订阅者。

  5. 灵活性:
    ✨ 发布订阅模式使得系统更加灵活,能够适应不同的业务需求。例如,订阅者可以选择性地订阅感兴趣的消息类型,或者根据消息的内容执行不同的操作。这种灵活性使得系统更容易适应变化,降低了维护成本。

    遵循的设计原则
    上述使用发布-订阅模式重构示例后的代码遵循了以下设计原则:👇

  1. 单一职责原则(Single Responsibility Principle, SRP):
    ✈️ 每个类(如 Message , MessagePublisher , MessageSubscriber , MessageSubscriptionManager , ChatRoom , ChatUser )都只负责一项功能或职责。例如,Message 类只负责封装消息内容,而 MessageSubscriptionManager 只负责管理订阅和消息的分发。

  2. 开闭原则(Open-Closed Principle, OCP):
    ✈️ 系统应该对扩展开放,对修改关闭。在上述实现中,如果需要添加新的消息类型或订阅者,不需要修改现有的代码,只需扩展相应的接口或类即可。例如,可以通过实现MessageSubscriber接口来创建新的订阅者。

  3. 里氏替换原则(Liskov Substitution Principle, LSP):
    ✈️ 子类必须能够替换其父类出现在任何地方,并且不会引入任何错误或异常。虽然上述示例中没有直接展示继承关系,但如果有子类继承自 MessageSubscriber ,那么它们应该能够无缝地替换父类实例,而不需要修改 MessageSubscriptionManagerChatRoom 的代码。

  4. 接口隔离原则(Interface Segregation Principle, ISP):
    ✈️ 客户端不应该依赖于它不使用的接口。在上述实现中, MessagePublisherMessageSubscriber 接口都是小而专注的,只定义了与发布和订阅消息相关的操作,没有包含任何不相关的方法。

  5. 依赖倒置原则(Dependency Inversion Principle, DIP):
    ✈️ 高层模块不应该依赖于低层模块,它们都应该依赖于抽象。在上述实现中, ChatRoom 类依赖于抽象的 MessagePublisher 接口(通过 MessageSubscriptionManager 实现),而不是具体的实现类。这意味着如果需要更换消息发布的管理方式,只需要提供一个新的 MessagePublisher 实现,而不需要修改ChatRoom的代码。

  6. 迪米特法则(Law of Demeter, LoD)或最少知识原则(Least Knowledge Principle, LKP)::
    ✈️ 一个对象应该对其他对象保持最少的了解。在上述实现中, ChatRoom 只与 MessageSubscriptionManager 交互,而不直接与订阅者交互。同样,订阅者(如 ChatUser )也只与接收到的消息交互,而不需要知道消息是如何发布或管理的。

    缺点
    上述实现(假设是指使用发布订阅模式的实现)虽然解决了许多已知的问题,并遵循了良好的设计原则,但仍然可能存在一些潜在的缺点或考虑因素:👇

  1. 内存消耗:
    💡 如果订阅者数量众多或者消息产生频率非常高,系统可能会面临内存压力。因为每个订阅者都可能保留一份消息副本,或者中间层(如 MessageSubscriptionManager )需要维护大量的订阅关系和待处理消息。

  2. 消息处理顺序:
    💡 发布订阅模式通常不保证消息的处理顺序。如果有多个订阅者同时处理同一条消息,或者订阅者在不同线程/进程中运行,那么消息的处理顺序可能会变得不可预测。

  3. 消息丢失或重复:
    💡 在分布式系统或存在网络延迟/故障的环境中,发布订阅模式可能会面临消息丢失或重复的问题。需要额外的机制来确保消息的可靠传输和幂等性处理。

  4. 复杂性增加:
    💡 引入发布订阅模式可能会增加系统的复杂性。需要管理额外的组件(如消息代理、订阅管理器等),并处理它们之间的交互和依赖关系。此外,调试和维护一个复杂的消息传递系统也可能更加困难。

  5. 性能瓶颈:
    💡 如果所有消息都通过一个集中的 MessageSubscriptionManager 进行处理和分发,那么它可能会成为系统的性能瓶颈。特别是在高并发或大数据量的场景下,单点压力可能会很大。

  6. 安全性考虑:
    💡 发布订阅模式可能暴露更多的攻击面。例如,未经授权的订阅者可能会接收到敏感信息,或者恶意订阅者可能会发送伪造的消息来干扰系统的正常运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/752361.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jest:JavaScript的单元测试利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

作品展示ETL

1、ETL 作业定义、作业导入、控件拖拽、执行、监控、稽核、告警、报告导出、定时设定 欧洲某国电信系统数据割接作业定义中文页面&#xff08;作业顶层&#xff0c;可切英文&#xff0c;按F1弹当前页面帮助&#xff09; 涉及文件拆分、文件到mysql、库到库、数据清洗、数据转…

Vue mqtt 附在线mqtt客户端地址 + 完整示例

mqtt&#xff1a;轻量级物联网消息推送协议。 目录 一、介绍 1、官方文档 1&#xff09;npm网 2) 中文网 MQTT中文网_MQTT 物联网接入平台-MQTT.CN 2、官方示例 二、准备工作 1、安装依赖包 2、示例版本 三、使用步骤 1、在单页面引入 mqtt 四、完整示例 tips 一、介…

渐开线花键环规的几种加工方法

小伙伴们大家好&#xff0c;今天咱们聊一聊渐开线花键环规的几种加工方法。 渐开线花键环规是在汽车、摩托车以及机械制造工业应用非常广泛的一种检测量具。它属于是一种内花键齿轮&#xff0c;其精度和表面粗糙度要求都比较高。采用的加工方法也比较多&#xff0c;下面详细看…

【爬虫逆向】Python逆向采集猫眼电影票房数据

进行数据抓包&#xff0c;因为这个网站有数据加密 !pip install jsonpathCollecting jsonpathDownloading jsonpath-0.82.2.tar.gz (10 kB)Preparing metadata (setup.py) ... done Building wheels for collected packages: jsonpathBuilding wheel for jsonpath (setup.py) .…

Android VINF

周末搞这玩意欲仙欲死&#xff0c;没办法只有看看。VINTF是供应商接口对象&#xff08;VINTF 对象&#xff09;&#xff0c;准确的说&#xff0c;这个是属于兼容性矩阵概念。。。有点想起了以前看过的一个电影&#xff0c;异次元杀阵。。。下面是谷歌官方的图。 本质上其实就是…

C++之类和对象(3)

目录 1. 再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit 2. static成员 2.1 概念 3. 友元 3.1 友元函数 3.2 友元类 4. 内部类 5. 匿名对象 6. 拷贝对象时编译器做出的优化 1. 再谈构造函数 1.1 构造函数体赋值 class Date { public:Date(int year2024…

Helm Chart部署最简SpringBoot到K8S(AWS EKS版)

目标 这里假设&#xff0c;我们已经基本会使用k8s的kubectl命令进行部署了&#xff0c;也已经会自己打docker镜像推送到AWS ECR上面去了。而且&#xff0c;已经在云上准备好了AWS ECR镜像库和AWS EKS的k8s集群了。 这个前提上面&#xff0c;我们今天使用Helm Chart项目准备k8s…

数据结构试卷第九套

1.时间复杂度 2.树&#xff0c;森林&#xff0c;二叉树的转换 2.1树转二叉树 给所有的兄弟节点之间加一条连线&#xff1b;去线&#xff0c;只保留当前根节点与第一个叶子节点的连线&#xff0c;删除它与其他节点之间的连线&#xff1b;然后根据左孩子右兄弟进行调整&#xf…

个人网站制作 Part 11 添加用户权限管理 | Web开发项目

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加用户权限管理&#x1f528;使用Passport.js&#x1f527;步骤 1: 修改Passport本地策略 &#x1f528;修改用户模型&#x1f527;步骤 2: 修改用户模型 &#x1f528…

医学数据分析中缺失值的处理方法

医学数据分析中缺失值的处理方法 &#xff08;为了更好的展示&#xff0c;在和鲸社区使用代码进行展示&#xff09; 医学数据分析中&#xff0c;缺失值是不可避免的问题。缺失值的存在会影响数据的完整性和准确性&#xff0c;进而影响分析结果的可靠性。因此&#xff0c;在进…

中创ET4410台式电桥固件升级工具(修复了列表扫描的BUG)

中创ET4410台式LCR数字电桥固件升级工具和最新版固件&#xff08;修复了列表扫描的BUG&#xff09; 中创ET4410 台式LCR数字电桥 简单开箱测评&#xff1a;https://blog.zeruns.tech/archives/763.html 之前买的中创ET4410台式LCR数字电桥固件有BUG&#xff08;胜利的VC4090C…

FREERTOS中断配置和临界段

本文基础内容参考的是正点原子的FREERTOS课程。 这是基于HAL库的 正点原子手把手教你学FreeRTOS实时系统 这是基于标准库的 正点原子FreeRTOS手把手教学-基于STM32 回顾STM32的中断 什么是中断&#xff1f; 中断优先级分组设置 Freertos中断分组 Freertos就是用的最后一种&…

redis学习-redis介绍

目录 1.redis介绍 2.redis常用命令&#xff08;可以在官网的命令中查看redis的所有命令&#xff09; 2.1终端命令 2.2 redis通用命令 2.3五大基本类型的命令以及特殊情况分析 &#xff08;导航&#xff09; 3.事务 4. redis实现消息订阅 5. redis的两种持久化策略 …

KubeSphere集群安装-nfs分布式文件共享-对接Harbor-对接阿里云镜像仓库-遇到踩坑记录

KubeSphere安装和使用集群版 官网:https://www.kubesphere.io/zh/ 使用 KubeKey 内置 HAproxy 创建高可用集群:https://www.kubesphere.io/zh/docs/v3.3/installing-on-linux/high-availability-configurations/internal-ha-configuration/ 特别注意 安装前注意必须把当前使…

AG32 MCU以太网应用实例demo

一. 前言 AGM32系列32位微控制器旨在为MCU用户提供新的自由度和丰富的兼容外设&#xff0c;以及兼容的引脚和功能。AG32F407系列产品具有卓越的品质&#xff0c;稳定性和卓越的价格价值。 AG32产品线支持其所有接口外设尽可能接近主流兼容性&#xff0c;并提供丰富的参考设计…

排序算法:快速排序(非递归)

文章目录 一、先建立一个栈二、代码编写 !](https://img-blog.csdnimg.cn/direct/870dd101173d4522862e4459b32237a3.png) 先赞后看&#xff0c;养成习惯&#xff01;&#xff01;&#xff01;^ _ ^<3 ❤️ ❤️ ❤️ 码字不易&#xff0c;大家的支持就是我坚持下去的动力…

旧华硕电脑开机非常慢 电脑开机黑屏很久才显示品牌logo导致整体开机速度非常的慢怎么办

前提条件 电池需要20&#xff05;&#xff08;就是电池没有报废&#xff09;且电脑接好电源&#xff0c;千万别断电&#xff0c;电脑会变成砖头的 解决办法 更新bios即可解决&#xff0c;去对应品牌官网下载最新的bios版本就行了 网上都是一些更新驱动啊

传统机器学习 基于TF_IDF的文本聚类实现

简介 使用sklearn基于TF_IDF算法&#xff0c;实现把文本变成向量。再使用sklearn的kmeans聚类算法进行文本聚类。 个人观点&#xff1a;这是比较古老的技术了&#xff0c;文本转向量的效果不如如今的 text2vec 文本转向量好。 而且sklearn 不支持GPU加速&#xff0c;处理大量…

小狐狸ChatGPT智能聊天系统源码v2.7.6全开源Vue前后端+后端PHP

测试环境包括Linux系统的CentOS 7.6&#xff0c;宝塔面板&#xff0c;PHP 7.4和MySQL 5.6。网站的根目录是public&#xff0c; 使用thinkPHP进行伪静态处理&#xff0c;并已开启SSL证书。 该系统具有多种功能&#xff0c;包括文章改写、广告营销文案创作、编程助手、办公达人…