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

探索设计模式的魅力:捕捉变化的风-用观察者模式提升用户体验


设计模式专栏:http://t.csdnimg.cn/U54zu


目录

一、引言

 核心概念

 应用场景

 可以解决的问题

二、场景案例

2.1 不用设计模式实现

2.2 存在问题

2.3 使用设计模式实现

2.4 成功克服

三、工作原理

3.1 结构图和说明

3.2 工作原理详解

3.3 实现步骤

四、 优势

4.1 好处和优势

4.2 应用示例

4.3 系统性优势

五、局限性和注意事项

5.1 局限性与不适用的场景

5.2 实际应用中的注意事项与建议


一、引言

 核心概念

    优雅方案

  • 在现代软件开发中,我们经常面临着如何实现不同组件之间的高效通信动态响应的问题。而观察者模式就是一个重要的设计模式,它提供了一种 elegant 的解决方案。

    观察者模式的核心概念主要包含以下几个关键部分:

 1. 主题(Subject)

  • 也称为被观察者或发布者,是核心组件之一。主题拥有维护一系列观察者的能力,提供注册(添加)和注销(移除)观察者的接口。当主题对象的状态发生变化时,它负责通知所有注册的观察者。

 2. 观察者(Observer)

  • 是一个接口或抽象类,规定了当主题的状态发生变化时应该执行的更新操作。具体观察者实现该接口,定义了在接收到主题状态变化通知时的具体行为。

 3. 具体主题(Concrete Subject)

  • 实现或继承主题接口的类。维护观察者的列表,并实现通知观察者的具体逻辑。

 4. 具体观察者(Concrete Observer)

  • 实现或继承观察者接口的类。当接收到主题的状态变化通知时,具体观察者会按定义的逻辑进行更新或其他响应。

 5. 状态(State)

  • 就是主题对象维护的、观察者感兴趣的数据。当状态发生变化时,主题会触发一个通知流程来更新所有的观察者。

 6. 更新接口(Update Method)

  • 是观察者定义的方法,在被主题通知时被调用用以更新自身状态。

  简单而言

    观察者模式允许对象之间建立一种一对多的依赖关系,当一个对象改变状态时,所有依赖它的对象都会得到通知并且自动更新。这种通知机制使得对象之间的通信更加松散耦合、灵活可扩展。无需直接相互引用,各个对象能够独立变化而互不影响。通过观察者模式,我们能够轻松实现实时更新、动态同步等功能,从而为我们的应用带来更好的用户体验和可维护性。无论是构建响应式界面、事件驱动系统,还是实现即时通信、发布-订阅模式,观察者模式都是一个不可或缺的设计选择。

    接下来,让我们深入探索观察者模式的内部工作原理和实际应用案例,享受软件开发的乐趣吧! 

 应用场景

  观察者模式在软件设计中的应用场景

 1. 用户界面(UI)交互

  • 当用户操作引发状态变化,比如一个按钮点击导致数据更新,观察者模式确保相关UI组件同步刷新。

 2. 事件监测系统

  • 系统中的某些事件发生时,如文件下载完成或硬件状态变更,观察者模式通知所有订阅者执行适当的动作。

 3. 发布/订阅系统

  • 在消息队列或实时消息服务中,产生消息的发布者与消费消息的订阅者无需知晓对方的存在。

 4. 数据模型与视图同步

  • 在MVC架构中,数据模型的更改需要能够实时地反映到视图上,观察者模式在此场景下保持视图和数据的一致性。

 可以解决的问题

    在现代软件开发中,组件间的交互和状态同步是一项常见而又至关重要的挑战。随着业务逻辑的复杂化及用户需求的不断变化,如何设计出灵活、低耦合的系统成为软件工程师面临的一大课题。对于系统中存在的一个实体状态改变需要通知到一个或多个依赖该状态的实体的场景,如何高效率地处理这种状态同步与通知呢?传统的紧耦合联系很难应对系统的迅速变化和扩展,而观察者模式在此场景下应运而生,提供了一种优雅且实用的设计解决方案。

  使用观察者模式可以解决的问题包括但不限于

  1. 解耦系统组件:降低对象之间的直接交互,实现松耦合,从而改善组件间的交互模式。
  2. 实现广播通信:当我们希望状态的改变能够通知到所有相关的依赖者而不是单一对象时,观察者模式提供了有效的机制。
  3. 动态交互:允许系统在运行时动态地新增或移除观察者,无需修改主题或其他观察者的代码。
  4. 推拉模型的支持:提供了推模型(主题向观察者推送详细信息)和拉模型(观察者自行获取其所需要的信息)两种方式。

        

二、场景案例

 经典场景:新闻发布系统

    最经典的观察者模式场景之一是“新闻发布系统”。在这个场景中,有多个订阅者(观察者)对新闻感兴趣,他们希望在有新闻发布时能够立即得到通知。系统管理员(主题)负责发布新闻。

2.1 不用设计模式实现

 一坨坨代码实现

import java.util.ArrayList;  
import java.util.List;  // 新闻类  
class News {  private String content;  public News(String content) {  this.content = content;  }  public String getContent() {  return content;  }  
}  // 新闻发布器  
class NewsPublisher {  private List<NewsSubscriber> subscribers = new ArrayList<>();  // 订阅新闻  public void subscribe(NewsSubscriber subscriber) {  subscribers.add(subscriber);  }  // 取消订阅  public void unsubscribe(NewsSubscriber subscriber) {  subscribers.remove(subscriber);  }  // 发布新闻  public void publish(News news) {  for (NewsSubscriber subscriber : subscribers) {  subscriber.receiveNews(news);  }  }  
}  // 新闻订阅者接口  
interface NewsSubscriber {  void receiveNews(News news);  
}  // 网页新闻订阅者  
class WebNewsSubscriber implements NewsSubscriber {  @Override  public void receiveNews(News news) {  System.out.println("WebNewsSubscriber: News received - " + news.getContent());  }  
}  // 邮件新闻订阅者  
class EmailNewsSubscriber implements NewsSubscriber {  @Override  public void receiveNews(News news) {  System.out.println("EmailNewsSubscriber: News received - " + news.getContent());  }  
}  // 客户端代码  
public class NewsSystemClient {  public static void main(String[] args) {  NewsPublisher publisher = new NewsPublisher();  NewsSubscriber webSubscriber = new WebNewsSubscriber();  NewsSubscriber emailSubscriber = new EmailNewsSubscriber();  publisher.subscribe(webSubscriber);  publisher.subscribe(emailSubscriber);  News news = new News("Breaking News: World Peace Achieved!");  publisher.publish(news);  }  
}

    在这个实现中,NewsPublisher 类充当了新闻发布的中心角色,它维护了一个订阅者列表。当有新闻发布时,NewsPublisher 会遍历订阅者列表,并调用每个订阅者的 receiveNews 方法来传递新闻。 

2.2 存在问题

    上述不使用设计模式实现的新闻发布系统确实存在一些问题,尽管它能够实现基本的新闻发布和接收功能。以下还是存在如紧耦合缺乏灵活性可扩展性差错误处理不足缺乏抽象层次 动态性受限 等问题。

2.3 使用设计模式实现

 1. 观察者接口(Observer):定义一个更新方法,当新闻发布时,所有观察者都将调用此方法。

public interface Observer {  void update(String news);  
}

 2. 具体观察者(ConcreteObserver):实现观察者接口,当有新闻发布时,执行具体的操作。例如,将新闻显示在网页上、发送到用户的电子邮箱等。

public class WebObserver implements Observer {  @Override  public void update(String news) {  System.out.println("WebObserver: Display news on website - " + news);  }  
}  public class EmailObserver implements Observer {  @Override  public void update(String news) {  System.out.println("EmailObserver: Send news to email - " + news);  }  
}

 3. 主题接口(Subject):定义一个注册观察者、移除观察者和通知观察者的方法。

import java.util.ArrayList;  
import java.util.List;  public interface Subject {  void registerObserver(Observer observer);  void removeObserver(Observer observer);  void notifyObservers(String news);  
}

 4. 具体主题(ConcreteSubject):实现主题接口,维护一个观察者列表,并在有新闻发布时通知所有观察者。

public class NewsSubject implements Subject {  private List<Observer> observers = new ArrayList<>();  @Override  public void registerObserver(Observer observer) {  observers.add(observer);  }  @Override  public void removeObserver(Observer observer) {  observers.remove(observer);  }  @Override  public void notifyObservers(String news) {  for (Observer observer : observers) {  observer.update(news);  }  }  
}

 5. 客户端代码(Client):创建主题和观察者对象,并将观察者注册到主题上。当有新闻发布时,主题会通知所有观察者。

public class Client {  public static void main(String[] args) {  NewsSubject newsSubject = new NewsSubject();  Observer webObserver = new WebObserver();  Observer emailObserver = new EmailObserver();  newsSubject.registerObserver(webObserver);  newsSubject.registerObserver(emailObserver);  newsSubject.notifyObservers("Breaking News: World Peace Achieved!");  }  
}

    在这个场景中,新闻发布系统(主题)负责发布新闻,而网页观察者(WebObserver)和电子邮件观察者(EmailObserver)则负责在新闻发布时显示和发送新闻。通过使用观察者模式,系统管理员可以轻松地添加或移除观察者,而无需修改主题代码。此外,当有新闻发布时,所有观察者都会自动收到通知并更新,从而实现了松耦合和可扩展性。 

2.4 成功克服

    使用观察者模式在上述示例中成功克服了多个问题,这些问题在使用直接的方法调用和对象间显式交互时可能会出现。以下是观察者模式成功克服的问题:

 1. 紧耦合

  • 观察者模式通过引入抽象和接口,降低了新闻发布器(主题)和订阅者(观察者)之间的耦合度。这意味着如果新闻发布器的内部实现发生变化,只要它继续遵循观察者模式的接口,订阅者的代码就不需要修改。

 2. 缺乏灵活性

  • 观察者模式允许主题和观察者之间的解耦,从而提高了系统的灵活性。这意味着可以更容易地支持多种不同的订阅场景,比如特定的时间间隔接收新闻或只接收特定类型的新闻。

 3. 可扩展性差

  • 通过引入抽象和接口,观察者模式允许更容易地扩展系统。例如,可以轻松地添加新的观察者类型,而不需要修改现有的代码。此外,由于观察者模式的通知机制是异步的,它也可以更好地处理大量观察者的情况,避免性能问题。

 4. 错误处理不足

  • 观察者模式允许在观察者中实现错误处理逻辑。这意味着如果某个订阅者在接收新闻时出现问题,它可以优雅地处理这些错误,而不会影响到新闻发布器或其他订阅者。

 5. 缺乏抽象层次

  • 观察者模式通过引入抽象和接口,为系统提供了更好的抽象层次。这使得系统更易于进行单元测试和维护,因为可以针对抽象接口编写测试,而不是针对具体的实现。

 6. 动态性受限

  • 观察者模式允许观察者在运行时动态地注册和注销,从而提高了系统的动态性。这意味着可以更容易地支持动态添加或删除订阅者的需求。

        

三、工作原理

3.1 结构图和说明

  • Subject:目标对象,通常具有如下功能。
  • Observer:定义观察者的接又,提供目标通知时对应的更新方法,这个更新方法进行相应的业务处理,可以在这个方法里面回调目标对象,以获取目标对象的数据。
  • ConcreteSubject:具体的目标实现对象,用来维护目标状态,当目标对象的状态发生改变时,通知所有注册的、有效的观察者,让观察者执行相应的处理

  • ConcreteObserver:观察者的具体实现对象,用来接收目标的通知,并进行相应的后续处理,比如更新自身的状态以保持和目标的相应状态一致。

3.2 工作原理详解

 1. 注册与订阅

  • 首先,观察者需要向被观察者注册或订阅感兴趣的事件或主题。这通常是通过调用被观察者的某个注册方法来实现的,该方法将观察者添加到其内部维护的观察者列表中。

 2. 状态变化

  • 当被观察者的状态发生变化时,它会通知所有已注册的观察者。这通常是通过调用一个通知方法来实现的,该方法遍历观察者列表并调用每个观察者的更新方法。

 3. 通知更新

  • 观察者接收到通知后,会根据自己的需要执行相应的操作或更新自己的状态。这通常是通过实现一个更新方法来完成的,该方法在被调用时会根据被观察者的新状态进行相应的处理。

 4. 解耦

  • 观察者模式的核心优势在于它实现了观察者和被观察者之间的解耦。被观察者不需要知道具体的观察者是谁,也不需要关心观察者如何响应状态变化。同样,观察者也不需要知道被观察者的具体实现细节,只需要关心自己感兴趣的事件或主题。

 5. 灵活性和扩展性

  • 由于观察者和被观察者之间的解耦关系,我们可以在不修改现有代码的情况下添加新的观察者或更改观察者的行为。这为软件系统的灵活性和扩展性提供了很好的支持。

3.3 实现步骤

    使用观察者模式实现功能时,你可以按照以下思考步骤进行:

 1. 定义主题和观察者之间的关系

  • 确定哪个对象应当作为主题,即数据变化的源头。
  • 识别哪些对象应当作为观察者,即需要响应数据变化的对象。
  • 设计一种方式让观察者能够订阅并从主题接收更新。

 2. 设计通用接口

  • 为观察者定义统一的接口,以便主题更新数据时能够通知所有观察者。
  • 考虑定义主题接口,描述如何注册、注销观察者,以及怎样发出通知。

 3. 实现注册与移除观察者功能

  • 主题需要提供方法让观察者能够注册自己或者被移除。
  • 主题内部需要有机制跟踪所有注册的观察者。

 4. 定义通知机制

  • 确定更新状态后观察者被通知的机制是推送还是拉取。
  • 设计主题在状态更改时如何通知观察者的逻辑。

 5. 更新观察者状态

  • 观察者接口中应定义如何更新其状态以响应主题状态变化的方法。
  • 实现观察者根据接收到的更新来进行自身状态更改或相应行为的逻辑。

 6. 考虑线程安全与性能问题

  • 如果在多线程环境下,确保主题在通知观察者时的线程安全性。
  • 分析性能问题,确保通知机制不会成为瓶颈。

 7. 实现解耦

  • 观察者和主题应该保持松耦合,以便独立变化而不影响彼此。

 8. 处理异常与错误

  • 确保即便某个观察者处理失败,也不应影响到主题和其他观察者。

 9. 测试

  • 对主题、观察者以及整个通知机制进行测试,确保满足需求。
  • 验证在增加或删除观察者、变更主题状态时,系统行为正确无误。

 10. 细节优化

  • 根据反馈和测试结果优化设计,可能涉及提高性能、简化接口、增强用户体验等。

     在应用观察者模式时,始终需要关注设计的整体清晰度、灵活性以及扩展性,确保最终实现的模式适合应用的上下文环境。

        

四、 优势

4.1 好处和优势

    使用观察者模式可以带来以下明显的好处和优势:

 1. 解耦

  • 观察者模式实现了观察者和被观察者之间的解耦,这意味着两者之间的依赖关系变得更加松散。这种解耦关系有助于提高代码的可维护性和可重用性,因为你可以在不修改被观察者代码的情况下添加或删除观察者。

 2. 灵活性

  • 由于观察者和被观察者之间的解耦关系,你可以灵活地添加、删除或更改观察者,而无需修改被观察者的代码。这为系统的扩展和修改提供了极大的便利。

 3. 动态响应

  • 观察者模式允许被观察者在其状态发生变化时自动通知所有相关的观察者。这种动态响应机制使得系统能够实时地响应变化,从而提高了系统的响应速度和效率。

 4. 简化通信

  • 观察者模式提供了一种简洁而有效的方式来处理不同组件之间的通信。通过观察者和被观察者之间的注册、通知和更新机制,你可以轻松地实现组件之间的通信和协作。

4.2 应用示例

    考虑一个电商平台上的商品定价系统。传统的设计方法可能会要求每个依赖商品价格信息的组件都直接从价格数据库中获取更新。随着系统的发展,这种紧耦合的方式导致了若干问题:每当价格更新逻辑变化时,所有依赖组件都需要作出相应修改;系统的可扩展性差,添加新的依赖组件会带来额外的维护负担。
    采用观察者模式改进后,价格系统作为主题,各个依赖组件(如库存管理、促销引擎、前端显示等)作为观察者。当商品价格更新时,价格系统仅需通知这些观察者。这样,库存管理系统可以自动调整库存采购策略,促销引擎可以同步更新促销活动,用户界面也可以即时显示最新价格。这种方式不仅使得价格更新流程更加清晰,而且让各组件能够更加独立地开发和维护。

4.3 系统性优势

    观察者模式通过解耦观察者和被观察者之间的关系,提高了系统的灵活性、扩展性和可维护性。具体来说:

 1. 灵活性

  • 由于观察者和被观察者之间的解耦关系,你可以在不修改现有代码的情况下添加新的观察者或更改观察者的行为。这为系统的灵活性提供了很好的支持。

 2. 扩展性

  • 观察者模式允许你轻松地扩展系统的功能。例如,你可以添加新的观察者来处理新的事件或主题,而无需修改现有的代码。这种扩展性使得系统能够适应不断变化的需求。

 3. 可维护性

  • 由于观察者模式降低了对象之间的耦合度,代码变得更加清晰和易于维护。当一个对象的状态发生变化时,你只需要修改被观察者的代码,而无需关心与之相关的多个对象的代码。这大大降低了维护成本和出错的可能性。

    综上所述,观察者模式通过解耦观察者和被观察者之间的关系,提高了系统的灵活性、扩展性和可维护性。它简化了对象之间的通信和协作,使得代码更加清晰、简洁和易于维护。因此,在现代软件开发中,观察者模式被广泛应用于处理不同组件之间的高效通信和动态响应问题。 

        

五、局限性和注意事项

5.1 局限性与不适用的场景

    尽管观察者模式为软件开发带来了许多好处,但在某些情况下,它也可能存在局限性和不适用的场景:

 1. 复杂的依赖关系

  • 当系统中的依赖关系变得非常复杂时,观察者模式可能会增加理解和维护的难度。如果观察者之间或观察者与被观察者之间存在复杂的交互逻辑,可能会导致代码变得难以理解和维护。

 2. 性能考虑

  • 在大型系统中,如果观察者数量众多,每次被观察者状态变化时都需要通知所有观察者,这可能会导致性能问题。过多的通知操作可能会消耗大量的计算资源和带宽,影响系统的整体性能。

 3. 循环依赖

  • 如果不小心处理,观察者模式可能会导致循环依赖的问题。例如,观察者A订阅了被观察者B的变化,同时被观察者B又订阅了观察者A的变化。这种情况下,当被观察者B的状态发生变化时,它会通知观察者A,而观察者A在更新自己的状态时又会触发被观察者B的通知,从而形成一个无限循环。

 4. 错误处理

  • 在观察者模式中,当通知观察者时,如果被观察者的通知方法抛出异常,这可能会导致整个系统的不稳定。如果没有妥善处理这些异常,可能会导致系统崩溃或不可预知的行为。

5.2 实际应用中的注意事项与建议

 1. 推送 vs 拉取

  • 在通知观察者时,可以选择推送通知(将状态变化的具体数据发送给观察者)或拉取通知(仅通知观察者去主题上获取需要的数据)。推送方式可能会导致观察者接收不需要的数据,而拉取方式可能导致观察者不知道哪些数据有更新。设计时需要根据实际情况选择更合适的通知机制。

 2. 通知顺序

  • 多个观察者注册到同一个主题时,观察者接收通知的具体顺序可能会影响系统行为。如果某种顺序有特定的业务意义,应该在设计中明确其顺序,并在可能的情况下保持这个顺序的一致性。

 3. 通知效率

  • 如果观察者数量较多或者更新操作比较耗时,主题在通知所有观察者时可能会遭遇性能瓶颈。想要缓解这种情况,可以考虑异步通知机制或使用消息队列处理。

 4. 循环依赖

  • 某个观察者在接收到更新通知后,可能会反过来影响主题状态,从而触发新的通知。该情况如果不加以控制,可能会造成循环调用的问题。设计时要注意辨识并处理潜在的循环依赖问题。

 5. 内存管理

  • 主题通常持有对所有观察者的引用,如果不恰当地进行监听和解除监听,可能会导致内存泄漏。需要确保在观察者生命周期结束时,从主题中正确移除其引用。

 6. 异常处理

  • 当观察者在接收通知时发生异常,不应中断整个通知过程。应该处理每个观察者的异常,尽量减少他们对其他观察者和主题的影响。

 7. 状态一致性

  • 确保观察者在任何时候获取的状态都是一致的。这意味着在状态变更和通知期间,应阻止对状态的任何修改,或者采用一些机制(如状态快照)来保持状态的一致性。

 8. 设计模式的组合使用

  • 有时单纯使用观察者模式可能不足以解决所有问题,可能需要与其他设计模式结合使用,比如命令模式、状态模式或策略模式等,以实现更灵活和健壮的设计。

    在遵守这些注意事项和建议的同时,应该记住设计模式不是万能的,不应该强行适配模式。在选择应用观察者模式前,确保它适合当前的问题场景,并充分考虑它可能带来的设计复杂性。

相关文章:

探索设计模式的魅力:捕捉变化的风-用观察者模式提升用户体验

设计模式专栏&#xff1a;http://t.csdnimg.cn/U54zu 目录 一、引言 核心概念 应用场景 可以解决的问题 二、场景案例 2.1 不用设计模式实现 2.2 存在问题 2.3 使用设计模式实现 2.4 成功克服 三、工作原理 3.1 结构图和说明 3.2 工作原理详解 3.3 实现步骤 四、 优…...

SpringCloud-高级篇(十九)

我们已经学过使用 SpringAMQP去收和发消息&#xff0c;但是发和收消息是只是MQ最基本的功能了&#xff0c;在收发消息的过程中&#xff0c;会有很多的问题需要去解决&#xff0c;下面需要学习rabbitMQ的高级特性去解决 死信交换机&#xff1a;这个可以帮助我们实现消息的延迟的…...

Junit常用断言

0.断言简介 断言:assert Q:断言的作用 更方便的对结果进行判定 "有针对性"的if判断 针对两个变量值是否相同 使用assertEquals针对两个对象是否相同 使用assertSame针对返回值是否为True 使用assertTrue 1.断言的参数 assertXXX(”断言失败时提升的信息“&#x…...

docker 实现 mysql:8.3.0 主从复制(2024年2月13日最新版本)

环境为 CentOS 7.6&#xff0c; 具体操作请看MySQL主从复制01-主从复制概述及原理_哔哩哔哩_bilibili 1、配置主服务器 # 启动主服务器 docker run -p 3306:3306 --name mysql_master -e MYSQL_ROOT_PASSWORDnmnmnm67890890 -v /docker/mysql_master/conf:/etc/mysql/conf.d…...

STM32 + ESP8266,连接阿里云 上报/订阅数据

&#xff08;文章正在编辑中&#xff0c;一点点地截图操作过程&#xff0c;估计要拖拉两三天&#xff09; 一、烧录MQTT固件 ESP8266出厂时&#xff0c;默认是AT固件。连接阿里云&#xff0c;需要使用MQTT固件。 1、独立EPS8266模块的烧录方法 2、魔女开发板&#xff0c;板载…...

如何利用chatgpt提升工作效率?

在数字化和信息化的时代&#xff0c;人工智能技术已经深入到了我们生活的方方面面。其中&#xff0c;ChatGPT作为当前热门的人工智能技术&#xff0c;以其强大的自然语言处理能力和广泛的应用场景&#xff0c;正逐渐改变着我们的工作方式&#xff0c;为我们提高工作效率提供了全…...

MongoDB聚合:$geoNear

$geoNear根据指定的点按照距离以由近到远的顺序输出文档。 从4.2版本开始&#xff0c;MongoDB移除了limit和num选项以及100个文档的限制&#xff0c;如果要限制结果文档的数量可以使用$limit阶段。 语法 { $geoNear: { <geoNear options> } }$geoNear操作接受一个包含…...

Docker-CE 国内源国内镜像

Docker-CE 就是 Docker Community Edition 的意思 docker-ce由docker官方维护 , docker.io由Debian维护 Docker官文 – Install Docker Engine on CentOS Docker官文 – Install Docker Engine on Fedora Docker官文 – Install Docker Engine on Debian Docker官文 – In…...

【Tauri】(3):使用Tauri1.5版本,进行桌面应用开发,在windows上搭建环境,安装node,rust环境,可以打包成功,使用vite创建应用

1&#xff0c;视频地址&#xff1a; https://www.bilibili.com/video/BV1Ny421a7nA/ 【Tauri】&#xff08;3&#xff09;&#xff1a;使用Tauri1.5版本&#xff0c;进行桌面应用开发&#xff0c;在windows上搭建环境&#xff0c;安装node&#xff0c;rust环境&#xff0c;可以…...

C++ 堆排序

C 堆排序 堆排序是一种基于二叉堆数据结构的排序算法&#xff0c;其原理如下&#xff1a; 构建最大堆&#xff1a;将待排序的数组看作一个完全二叉树&#xff0c;并通过调整节点的位置构建一个最大堆。最大堆满足每个父节点的值都大于或等于其子节点的值。构建最大堆的过程可以…...

U3D记录之FBX纹理丢失问题

今天费老大劲从blender建了个模型&#xff0c;然后导出进去unity 发现贴图丢失 上网查了一下 首先blender导出要改设置 这个path mode要copy 然后unity加载纹理也要改设置 这里这个模型的纹理load要改成external那个模式 然后就有了&#xff0c;另外这个导出还有好多选项可…...

监测Nginx访问日志502情况后并做相应动作

今天带大家写一个比较实用的脚本哈 原理&#xff1a; 假设服务器环境为lnmp&#xff0c;近期访问经常出现502现象&#xff0c;且502错误在重启php-fpm服务后消失&#xff0c;因此需要编写监控脚本&#xff0c;一旦出现502&#xff0c;则自动重启php-fpm服务 场景&#xff1a; 1…...

【数据分享】1929-2023年全球站点的逐年平均风速(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 有关气象指标的监测站点数据&#xff0c;之前我们分享过1929-2023年全球气象站…...

Android性能调优 - 应用安全问题

Android应用安全 1.组件暴露&#xff1a; 像比如ContentProvider,BroadcastReceiver&#xff0c;Activity等组件有android:exported属性&#xff1b; 如果是私有组件 android:exported “false”&#xff1b; 如果是公有组件 android:exported “true” 且进行权限控制&…...

C#的Char 结构的像IsLetterOrDigit(Char)等常见的方法

目录 一、Char 结构的方法 二、Char.IsLetterOrDigit 方法 1.Char.IsLetterOrDigit(Char)用法 2.IsLetterOrDigit(String, Int32)方法 三、Char.IsLetter 方法 1.IsLetter(Char) 2.IsLetter(String, Int32) 四、Char.IsDigit 方法 1. IsDigit(String, Int32) 2.IsDig…...

部分意图分类【LLM+RAG】

在生成人工智能领域工作最有价值的事情之一就是发现新兴技术如何融入新的解决方案。 举个例子&#xff1a;在为北美顶级金融服务公司之一设计对话式人工智能助手时&#xff0c;WillowTree 的数据和人工智能研究团队 (DART) 发现&#xff0c;将意图分类与大型语言模型 (LLM) 结合…...

1277. 统计全为 1 的正方形子矩阵

1277. 统计全为 1 的正方形子矩阵 题目链接&#xff1a;1277. 统计全为 1 的正方形子矩阵 代码如下&#xff1a; class Solution { public:int countSquares(vector<vector<int>>& matrix) {if(matrix.size()0||matrix[0].size()0) return 0;//dp[i][j]代表…...

Python 3 时间序列可视化指南

简介 时间序列分析属于统计学的一个分支&#xff0c;涉及对有序的、通常是时间性的数据进行研究。当适当应用时&#xff0c;时间序列分析可以揭示意想不到的趋势&#xff0c;提取有用的统计数据&#xff0c;甚至预测未来的趋势。因此&#xff0c;它被应用于许多领域&#xff0…...

[算法前沿]--059-大语言模型Fine-tuning踩坑经验之谈

前言 由于 ChatGPT 和 GPT4 兴起,如何让人人都用上这种大模型,是目前 AI 领域最活跃的事情。当下开源的 LLM(Large language model)非常多,可谓是百模大战。面对诸多开源本地模型,根据自己的需求,选择适合自己的基座模型和参数量很重要。选择完后需要对训练数据进行预处…...

【Docker】01 Docker安装与配置

文章目录 一、Docker二、离线安装Docker三、联网安装Docker3.1 下载YUM软件库文件3.2 安装epel-release3.3 安装yum-utils3.4 设置镜像仓库3.5 查看docker-ce所有版本3.6 安装Docker3.7 启动Docker3.8 查看Docker信息3.9 启动第一个容器 四、一些配置4.1 登录DockerHub4.2 镜像…...

Unity3d Shader篇(六)— BlinnPhong高光反射着色器

文章目录 前言一、BlinnPhong高光反射着色器是什么&#xff1f;1. BlinnPhong高光反射着色器的工作原理2. BlinnPhong高光反射着色器的优缺点优点缺点 3. 公式 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数 三…...

Go-zero微服务个人探究之路(十二)定时任务的选择调研

前言 很多时候后台需要做定时任务的需求&#xff0c;笔者的项目采用go-zero框架微服务框架&#xff0c;需要做定时任务&#xff0c;于是做了如下方法调研&#xff0c;共有大概三种主要选择 方案 难度总体由容易到复杂 go的timer库 通过Go的标准库time中的Ticker和Tick功能…...

Java中,List、Map和Set的区别是什么?

在Java中&#xff0c;List、Map和Set是三种常用的集合类型&#xff0c;它们之间的主要区别如下&#xff1a; 1、List List是有序集合&#xff0c;它可以包含重复元素。 List中的元素是按照插入顺序排列的&#xff0c;可以通过索引访问每个元素。 Java中常见的List实现类有A…...

Google刚刚推出了图神经网络Tensorflow-GNN

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

链表基础知识汇总

链表 链表是一种基本的数据结构&#xff0c;是由一系列节点组成的集合。每个节点包含两个部分&#xff1a;值和指向下一个节点的指针。链表中的节点可以动态地添加、删除&#xff0c;其大小可以根据需要进行扩展或缩小。 链表通常用于处理不固定长度的数据结构&#xff0c;具有…...

Educational Codeforces Round 2(远古edu计划)

A. 恶心模拟。。 模拟一下分类即可 数字类&#xff0c;数字0&#xff0c;或者都是数字 字母类&#xff0c;字母空的也是字母&#xff0c;有字母就是字母 #include<bits/stdc.h> #define INF 1e9 using namespace std; typedef long long ll; const int N2e59; strin…...

【Tauri】(1):使用Tauri1.5版本,进行桌面应用开发,在windows,linux进行桌面GUI应用程序开发,可以打包成功,使用 vite 最方便

1&#xff0c;视频地址&#xff1a; https://www.bilibili.com/video/BV1Pz421d7s4/ 【Tauri】&#xff08;1&#xff09;&#xff1a;使用Tauri1.5版本&#xff0c;进行桌面应用开发&#xff0c;在windows&#xff0c;linux进行桌面GUI应用程序开发&#xff0c;可以打包成功&…...

「Linux」软件安装

MySQL5.7在CentOS安装 安装 配置yum仓库 更新密钥&#xff1a;rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022安装MySQL yum库&#xff1a;rpm -Uvh http://repo.mysql.com//mysql57-community-release-el7-7.noarch.rpm使用yum安装MySQL&#xff1a;yum -y in…...

Ubuntu Desktop - Terminal 输出全部选中 + 复制

Ubuntu Desktop - Terminal 输出全部选中 复制 1. Terminal2. Terminal 最大化3. Edit -> Select All4. Copy & PasteReferences 1. Terminal 2. Terminal 最大化 3. Edit -> Select All 4. Copy & Paste Edit -> Copy or Shift Ctrl C Edit -> Paste…...

Java 三大并大特性-可见性介绍(结合代码、分析源码)

目录 ​编辑 一、可见性概念 1.1 概念 二、可见性问题由来 2.1 由来分析 三、可见性代码例子 3.1 代码 3.2 执行结果 四、Java 中保证可见性的手段 4.1 volatile 4.1.1 优化代码 4.1.2 测试结果 4.1.3 volatile原理分析 4.1.3.1 查看字节码 4.1.3.2 hotspot 层面…...

【漏洞复现】狮子鱼CMS某SQL注入漏洞01

Nx01 产品简介 狮子鱼CMS&#xff08;Content Management System&#xff09;是一种网站管理系统&#xff0c;它旨在帮助用户更轻松地创建和管理网站。该系统拥有用户友好的界面和丰富的功能&#xff0c;包括页面管理、博客、新闻、产品展示等。通过简单直观的管理界面&#xf…...

《Java 简易速速上手小册》第6章:Java 并发编程(2024 最新版)

文章目录 6.1 线程的创建和管理 - 召唤你的士兵6.1.1 基础知识6.1.2 重点案例&#xff1a;实现一个简单的计数器6.1.3 拓展案例 1&#xff1a;定时器线程6.1.4 拓展案例 2&#xff1a;使用 Executor 框架管理线程 6.2 同步机制 - 维持军队的秩序6.2.1 基础知识6.2.2 重点案例&a…...

C++初阶:容器(Containers)list常用接口详解

介绍完了vector类的相关内容后&#xff0c;接下来进入新的篇章&#xff0c;容器list介绍&#xff1a; 文章目录 1.list的初步介绍2.list的定义&#xff08;constructor&#xff09;3.list迭代器&#xff08; iterator &#xff09;4.string的三种遍历4.1迭代器4.2范围for循环 5…...

HARRYPOTTER: FAWKES

攻击机 192.168.223.128 目标机192.168.223.143 主机发现 nmap -sP 192.168.223.0/24 端口扫描 nmap -sV -p- -A 192.168.223.143 开启了21 22 80 2222 9898 五个端口&#xff0c;其中21端口可以匿名FTP登录&#xff0c;好像有点说法,百度搜索一下发现可以用anonymous登录…...

嵌入式Qt 第一个Qt项目

一.创建Qt项目 打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项 弹出New Project对话框&#xff0c;选择Qt Widgets Application 选择【Choose】按钮&#xff0c;弹出如下对话框 设置项目名称和路径&#xff0c;按照向导进行下一步 选…...

【OpenHarmony硬件操作】风扇与温湿度模块

文章目录 前言一、串行通信是什么二、IC2.1 IC是什么2.2 IC涉及到的线2.3 IC的时序三、风扇的操作3.1 关于 pcf85743.2 风扇的接口函数IO拓展芯片的定义初始化PCF8574初始化 IO拓展版的引脚属性开启和关闭风扇读状态四、温湿度传感器的使用4.1 初始化温湿度传感器</...

Vue3.4+element-plus2.5 + Vite 搭建教程整理

一、 Vue3Vite 项目搭建 说明&#xff1a; Vue3 最新版本已经基于Vite构建&#xff0c;关于Vite简介&#xff1a;Vite 下一代的前端工具链&#xff0c;前端开发与构建工具-CSDN博客 1.安装 并 创建Vue3 应用 npm create vuelatest 创建过程可以一路 NO 目前推荐使用 Vue R…...

STM32Cubmax stm32f103zet6 SPI通讯

一、基本概念 SPI 是英语 Serial Peripheral interface 的缩写&#xff0c;顾名思义就是串行外围设备接口。是 Motorola 首先在其 MC68HCXX 系列处理器上定义的。 SPI 接口主要应用在 EEPROM&#xff0c; FLASH&#xff0c;实时时 钟&#xff0c; AD 转换器&#xff0c;还有数…...

每日OJ题_位运算⑤_力扣371. 两整数之和

目录 力扣371. 两整数之和 解析代码 力扣371. 两整数之和 371. 两整数之和 难度 简单 给你两个整数 a 和 b &#xff0c;不使用 运算符 和 - &#xff0c;计算并返回两整数之和。 示例 1&#xff1a; 输入&#xff1a;a 1, b 2 输出&#xff1a;3示例 2&#xff1a; …...

Mysql中索引优化和失效

什么是索引 要了解索引优化和索引失效的场景就要先了解什么是索引 索引是一种有序的存储结构&#xff0c;按照单个或者多个列的值进行排序&#xff0c;以提升搜索效率。 索引的类型 UNIQUE唯一索引 不可以出现相同的值&#xff0c;可以有NULL值。 INDEX普通索引 允许出现相同…...

使用Python+OpenCV2进行图片中的文字分割(支持竖版)

扣字和分割 把图片中的文字&#xff0c;识别出来&#xff0c;并将每个字的图片抠出来&#xff1b; import cv2 import numpy as npHIOG 50 VIOG 3 Position []水平投影 def getHProjection(image):hProjection np.zeros(image.shape,np.uint8)# 获取图像大小(h,w)image.sh…...

Qt中程序发布及常见问题

1、引言 当我们写好一个程序时通常需要发布给用户使用&#xff0c;那么在Qt中程序又是如何实现发布的呢&#xff0c;这里我就来浅谈一下qt中如何发布程序&#xff0c;以及发布程序时的常见问题。 2、发布过程 2.1、切换为release模式 当我们写qt程序时默认是debug模式&#x…...

C语言第二十三弹---指针(七)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、sizeof和strlen的对比 1.1、sizeof 1.2、strlen 1.3、sizeof 和 strlen的对比 2、数组和指针笔试题解析 2.1、⼀维数组 2.2、二维数组 总结 1、si…...

用HTML5 + JavaScript绘制花、树

用HTML5 JavaScript绘制花、树 <canvas>是一个可以使用脚本 (通常为JavaScript) 来绘制图形的 HTML 元素。 <canvas> 标签/元素只是图形容器&#xff0c;必须使用脚本来绘制图形。 HTML5 canvas 图形标签基础https://blog.csdn.net/cnds123/article/details/112…...

Science重磅_让大模型像婴儿一样学习语言

英文名称: Grounded language acquisition through the eyes and ears of a single child 中文名称: 通过一个孩子的眼睛和耳朵基于实践学习语言 文章: https://www.science.org/doi/10.1126/science.adi1374 代码: https://github.com/wkvong/multimodalbaby 作者: Wai Keen V…...

Java 数据结构篇-实现红黑树的核心方法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 红黑树的说明 2.0 红黑树的特性 3.0 红黑树的成员变量及其构造方法 4.0 实现红黑树的核心方法 4.1 红黑树内部类的核心方法 &#xff08;1&#xff09;判断当前…...

【实战】一、Jest 前端自动化测试框架基础入门(中) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(二)

文章目录 一、Jest 前端自动化测试框架基础入门5.Jest 中的匹配器toBe 匹配器toEqual匹配器toBeNull匹配器toBeUndefined匹配器和toBeDefined匹配器toBeTruthy匹配器toBeFalsy匹配器数字相关的匹配器字符串相关的匹配器数组相关的匹配器异常情况的匹配器 6.Jest 命令行工具的使…...

【C语言 - 力扣 - 反转链表】

反转链表题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 题解1-迭代 假设链表为 1→2→3→∅&#xff0c;我们想要把它改成 ∅←1←2←3。 在遍历链表时&#xff0c;将当前节点的 next 指针改为指向前一个节点。由于节点没…...

ctfshow-php特性(web102-web115)

目录 web102 web103 web104 web105 web106 web107 web108 web109 web110 web111 web112 web113 web114 web115 实践是检验真理的 要多多尝试 web102 <?php highlight_file(__FILE__); $v1$_POST[V1]; $v2$_GET[v2]; $v3$_GET[v3]; $v4is_numeric($v2)and is…...

python系统学习Day1

section1 python introduction 文中tips只做拓展&#xff0c;可跳过。 PartOne introduction 首先要对于python这门语言有一个宏观的认识&#xff0c;包括特点和应用场景。 特点分析&#xff1a; 优势 提供了完善的基础代码库&#xff0c;许多功能不必从零编写简单优雅 劣势 运…...