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

观察者模式、订阅者发布者模式、vtk中的观察者模式

文章目录

  • 什么是观察者模式
  • vtk是如何实现的观察者模式.AddObserver
  • 什么时候使用观察者模式?什么使用订阅发布者模式?
  • 观察者模式的实现
  • 订阅发布者的实现
  • 总结
  • 知识补充:

什么是观察者模式

用于在对象之间建立一对多的依赖关系,当一个对象的状态发生变化时,其所依赖的所有对象都会收到通知并自动更新。

vtk是如何实现的观察者模式.AddObserver

在VTK(Visualization Toolkit)中,观察者模式通过AddObserver方法来实现。AddObserver方法允许一个对象(观察者)注册自己以便接收另一个对象(被观察者)的通知。被观察者对象在发生特定事件或状态变化时会调用已注册的观察者的相应方法,以便进行相应的处理或更新。

#include <vtkSmartPointer.h>
#include <vtkObject.h>
#include <vtkCommand.h>
#include <iostream>// 自定义观察者类
class CustomObserver : public vtkCommand
{
public:static CustomObserver* New(){return new CustomObserver;}virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData){if (caller){std::cout << "Received event: " << caller->GetClassName() << ", Event ID: " << eventId << std::endl;}}
};int main()
{// 创建一个被观察者对象vtkSmartPointer<vtkObject> observedObject = vtkSmartPointer<vtkObject>::New();// 创建一个观察者对象vtkSmartPointer<CustomObserver> observer = vtkSmartPointer<CustomObserver>::New();// 注册观察者对象到被观察者对象observedObject->AddObserver(vtkCommand::AnyEvent, observer);// 触发事件,通知观察者对象observedObject->InvokeEvent(vtkCommand::ModifiedEvent);return 0;
}
/*
我们首先创建了一个被观察者对象observedObject和一个自定义的观察者类CustomObserver。然后,使用AddObserver方法将观察者对象observer注册到被观察者对象上,通过指定事件ID(vtkCommand::AnyEvent表示任何事件)和观察者对象来建立它们之间的关联。最后,我们调用InvokeEvent方法来触发事件并通知观察者对象。当事件被触发时,执行观察者类中的Execute方法,打印出相关信息。
*/

什么时候使用观察者模式?什么使用订阅发布者模式?

  • 使用观察者模式的情况包括:

1.当一个对象的改变需要同时影响其他多个对象,并且不希望显式地指定这些对象时,可以使用观察者模式。

2.当一个对象的改变需要通知其他对象,但是不需要知道具体的接收者时,可以使用观察者模式。

3.当一个对象需要在改变时通知一组对象而无需知道具体对象时,可以使用观察者模式。

订阅发布者模式定义了一种一对多的依赖关系,允许多个订阅者(观察者)订阅一个发布者(被观察者),并在发布者状态改变时接收通知。与观察者模式不同的是,发布者和订阅者之间没有直接的依赖关系,它们通过消息队列、事件中心或者代理来进行通信。

  • 使用订阅发布者模式的情况包括:

当存在多个发布者和订阅者之间的松散关系时,可以使用订阅发布者模式。

当发布者和订阅者之间需要解耦,以便灵活地添加或移除发布者和订阅者时,可以使用订阅发布者模式。

当需要支持多对多的关系,即一个发布者可以有多个订阅者,一个订阅者也可以订阅多个发布者时,可以使用订阅发布者模式。

观察者模式的实现

// 观察者模式
/*** Observer Design Pattern** Intent: Lets you define a subscription mechanism to notify multiple objects* about any events that happen to the object they're observing.** Note that there's a lot of different terms with similar meaning associated* with this pattern. Just remember that the Subject is also called the* Publisher and the Observer is often called the Subscriber and vice versa.* Also the verbs "observe", "listen" or "track" usually mean the same thing.*/#include <iostream>
#include <list>
#include <string>
// 抽象观察者
/*
定义了析构函数,和update函数接口
*/
class IObserver
{
public:virtual ~IObserver(){};virtual void Update(const std::string &message_from_subject) = 0;
};
// 抽象被观察者
/*
定义了析构函数,和attach,detach,notify三个函数接口*/
class ISubject
{
public:virtual ~ISubject(){};virtual void Attach(IObserver *observer) = 0;virtual void Detach(IObserver *observer) = 0;virtual void Notify() = 0;
};// 具体被观察者
/*建议先看main函数,然后再看观察者类,然后再看被观察者类,
不然的话,你就不会知道:为什么被观察者类被称为:"tfboys类"或者是"时代少年团类"或者是"蔡徐坤类"
*/
// 现在咱们来看一下:一个完整的"tfboys"类是如何分装的?
class Subject : public ISubject
{
public:// 重写析构函数virtual ~Subject(){std::cout << "Goodbye, I was the Subject.\n"; // 再见了,我的粉丝们,tfboys于2017年9月正式宣布解散}/*** The subscription management methods.*/void Attach(IObserver *observer) override{list_observer_.push_back(observer); // tfboys将粉丝收集到他的个人列表中,也就是说tfboys会记每一位ta的粉丝!}void Detach(IObserver *observer) override{list_observer_.remove(observer); // 某个粉丝不再对ta进行关注,tfboys就将人家移除个人列表,这个私有列表是用list实现的,是一个双向链表,可以高效的添加与删除每位粉丝,但是查找的复制度是O(N)}void Notify() override // 看到下面的遍历,大家应该猜到了,这是tfboys在举办演唱会之前,对每一位粉丝进行通知,当然这函数不是单独调用的,因为这个函数还有一个message_变量{std::list<IObserver *>::iterator iterator = list_observer_.begin();HowManyObserver();while (iterator != list_observer_.end()){(*iterator)->Update(message_);++iterator;}}// 没错,这个是通知每一位粉丝的真正业务函数void CreateMessage(std::string message = "Empty"){this->message_ = message; // 先把演唱会的相关消息进行编写保存Notify();                 // 然后将消息散发给粉丝}// 这是一个debug的函数,用来输出tfboys的私人列表中,到底有几百万粉丝?void HowManyObserver(){std::cout << "There are " << list_observer_.size() << " observers in the list.\n";}/*** Usually, the subscription logic is only a fraction of what a Subject can* really do. Subjects commonly hold some important business logic, that* triggers a notification method whenever something important is about to* happen (or after it).*/// 这个函数其实和CreateMessage一样,只不过这个内置了信息// 不太清楚这个干嘛用的,我可以理解为每次都要发送一些固定的消息,然后我们懒得用CreateMessage编辑了void SomeBusinessLogic(){this->message_ = "Tomorrow will be a holiday!!!";//比如:重要通知:明天放假!!![doge]Notify();std::cout << "I'm about to do some thing important\n";}private:std::list<IObserver *> list_observer_;std::string message_;
};// 具体观察者
class Observer : public IObserver
{
public:// 重写了自己的构造函数,他是用一个被观察者类来初始化,这样一来,被观察者有任何消息,观察者都会收到消息// 就好比很多人都热爱追星: tfboys就是被观察者,他的粉丝就是观察者,所以理论上来说,被观察者干的活应该会更多一点//(所以,为了好记:观察者你可以看成"粉丝类",被观察者你可以看成"tfboys类")// 所以说,下面咱们来看一下,粉丝类是如何封装的Observer(Subject &subject) : subject_(subject) // 这里,我们的粉丝们比较专一,只能选择"时代少年团","tfboys","蔡徐坤"等等,其中的一位明星作为自己的偶像(被观察者){this->subject_.Attach(this);                                                     // tfboys的微博收到了订阅请求,恭喜tfboys收获一枚新粉丝!std::cout << "Hi, I'm the Observer \"" << ++Observer::static_number_ << "\".\n"; // 蔡徐坤,你好,我是你的一个新粉丝this->number_ = Observer::static_number_;                                        // 这是记录tfsboys粉丝的总数量,每位粉丝都可以看到                                        //}virtual ~Observer(){std::cout << "Goodbye, I was the Observer \"" << this->number_ << "\".\n"; // 粉丝被析构了}void Update(const std::string &message_from_subject) override // 这个函数是有tfboys调用的,他要去哪里开演唱会?{message_from_subject_ = message_from_subject; // 将信息保存到粉丝的手机里PrintInfo();                                  // 通知粉丝,tfboys要去哪里开演唱会了}void RemoveMeFromTheList(){subject_.Detach(this);std::cout << "Observer \"" << number_ << "\" removed from the list.\n"; // gege太令人失望了,一位粉丝默默地离开了ta的应援团}void PrintInfo() // 打印收到了什么新消息{std::cout << "Observer \"" << this->number_ << "\": a new message is available --> " << this->message_from_subject_ << "\n";}private:std::string message_from_subject_;Subject &subject_;static int static_number_;int number_;
};int Observer::static_number_ = 0;void ClientCode()
{// 一个被观察者 subject有"主体"的意思,可以理解为"被观察的主体"Subject *subject = new Subject;// 多个观察者Observer *observer1 = new Observer(*subject); // Hi, I'm the Observer "1".Observer *observer2 = new Observer(*subject); // Hi, I'm the Observer "2".Observer *observer3 = new Observer(*subject); // Hi, I'm the Observer "3".Observer *observer4;Observer *observer5;// subject->SomeBusinessLogic();subject->CreateMessage("Hello World! :D"); // 此时observer1,observer2,observer3都收到了被观察者发送的信息observer3->RemoveMeFromTheList();          // observer3不再观察subject->CreateMessage("The weather is hot today! :p"); // 此时只有observe1,observer2收到了消息observer4 = new Observer(*subject);                     // observer4加入了观察者observer2->RemoveMeFromTheList();   // observer2不再观察observer5 = new Observer(*subject); // observer5加入观察subject->CreateMessage("My new car is great! ;)"); // 此时只有observe1,observer2,observer5收到了消息observer5->RemoveMeFromTheList();                  // observer5不再观察observer4->RemoveMeFromTheList(); // observer4不再观察observer1->RemoveMeFromTheList(); // observer1不再观察delete observer5;delete observer4;delete observer3;delete observer2;delete observer1;delete subject;
}int main()
{ClientCode();return 0;
}
/*
Hi, I'm the Observer "1".
Hi, I'm the Observer "2".
Hi, I'm the Observer "3".
There are 3 observers in the list.
Observer "1": a new message is available --> Hello World! :D
Observer "2": a new message is available --> Hello World! :D
Observer "3": a new message is available --> Hello World! :D
Observer "3" removed from the list.
There are 2 observers in the list.
Observer "1": a new message is available --> The weather is hot today! :p
Observer "2": a new message is available --> The weather is hot today! :p
Hi, I'm the Observer "4".
Observer "2" removed from the list.
Hi, I'm the Observer "5".
There are 3 observers in the list.
Observer "1": a new message is available --> My new car is great! ;)
Observer "4": a new message is available --> My new car is great! ;)
Observer "5": a new message is available --> My new car is great! ;)
Observer "5" removed from the list.
Observer "4" removed from the list.
Observer "1" removed from the list.
Goodbye, I was the Observer "5".
Goodbye, I was the Observer "4".
Goodbye, I was the Observer "3".
Goodbye, I was the Observer "2".
Goodbye, I was the Observer "1".
Goodbye, I was the Subject.
*/

订阅发布者的实现

以下代码并没有用到异步,当然,异步才是正宗的订阅者发布者模式,我暂时是想不到如何改为异步通知,不过,下面的代码也暂时够我们理解 : 在订阅者发布者模式里面的中介是干什么的了

// 订阅者发布者模式
/** 有了上观察者模式的基础,我们先可以尝试编写一下他的升级版--订阅者发布者模式* 在这个模式中,随着tyboys名声大噪,"tfboys",再不需要自己主动通知粉丝了,* 他有了自己的助理,所有大小事宜都交给自己的助理去做*/
#include <iostream>
#include <vector>// 提前声明助理类,不然tfboys不认(其实就是cpp语法,声明前后顺序的问题)
/** 当我们提前声明一个类时,在这个类被完全定义之前,只可以定义该类的变量,但是不能使用该类的方法。*/
class Mediator;// 抽象观察者类
// 抽象粉丝类
class Observer
{
protected:Mediator *_mediator; // 中介者指针public:explicit Observer(Mediator *mediator) : _mediator(mediator){}virtual ~Observer() {}virtual void update() = 0;
};// 具体观察者类
/**具体粉丝类*/
class ConcreteObserver : public Observer
{
public:// 调用基类Observer的构造函数来初始化基类中的mediator_成员变量explicit ConcreteObserver(Mediator *mediator);~ConcreteObserver();void update() override;private:static int static_number_;int number_;
};
int ConcreteObserver::static_number_ = 0;// 抽象发布者类
// 抽象tfboys类
class Publisher
{
protected:Mediator *mediator; // 中介者指针public:explicit Publisher(Mediator *mediator) : mediator(mediator){std::cout << "Hi! I'm a Publisher" << std::endl;}virtual ~Publisher(){std::cout << "Goodbye! I'm a Publisher" << std::endl;}void publish();void setMediator(Mediator *mediator){this->mediator = mediator;}
};// 中介者类
class Mediator
{
private:// 放粉丝的std::vector<Observer *> observers; // 存储观察者指针public:Mediator(){std::cout << "Hi! I'm a Mediator" << std::endl; // 中介的诞生};~Mediator(){std::cout << "Goodbye! I'm a Mediator" << std::endl; // 中介的消亡};// 加粉丝void attach(Observer *observer){observers.push_back(observer);}// 清空某个粉丝void detach(Observer *observer){for (auto it = observers.begin(); it != observers.end(); ++it){if (*it == observer){observers.erase(it);break;}}}// 通知所有粉丝void notify(Publisher *publisher){for (auto observer : observers){observer->update();}}
};/********下面是对两个函数的定义*************/
void ConcreteObserver::update()
{std::cout << "Received an update from the publisher!" << std::endl;
}void Publisher::publish()
{std::cout << "Publishing an update..." << std::endl;mediator->notify(this);
}// 先声明后实现,有效的解决了循环依赖的问题!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ConcreteObserver::ConcreteObserver(Mediator *mediator) : Observer(mediator)
{this->_mediator->attach(this);std::cout << "Hi! I'm a ConcreteObserver" << ++ConcreteObserver::static_number_ << std::endl;this->number_ = ConcreteObserver::static_number_;
}
ConcreteObserver::~ConcreteObserver()
{std::cout << "Goodbye! I'm a ConcreteObserver" << this->number_ << std::endl;ConcreteObserver::static_number_--;this->_mediator->detach(this);
}int main()
{// tfboys的助理Mediator *mediator = new Mediator(); // 先来一个中介// tfboys绑定一个助理Publisher *publisher = new Publisher(mediator);// tfboys的粉丝Observer *observer1 = new ConcreteObserver(mediator); // 现在粉丝直接和助理进行关联Observer *observer2 = new ConcreteObserver(mediator);Observer *observer3;Observer *observer4;// 下面两行可以搞成异步的,但是我不知道怎么搞// mediator->attach(observer1);// mediator->attach(observer2);publisher->publish();observer3 = new ConcreteObserver(mediator);observer4 = new ConcreteObserver(mediator);publisher->publish();delete observer1;publisher->publish();delete observer2;delete observer3;delete observer4;delete publisher;delete mediator;return 0;
}
/*
Hi! I'm a Mediator
Hi! I'm a Publisher
Hi! I'm a ConcreteObserver1
Hi! I'm a ConcreteObserver2
Publishing an update...
Received an update from the publisher!
Received an update from the publisher!
Hi! I'm a ConcreteObserver3
Hi! I'm a ConcreteObserver4
Publishing an update...
Received an update from the publisher!
Received an update from the publisher!
Received an update from the publisher!
Received an update from the publisher!
Goodbye! I'm a ConcreteObserver1
Publishing an update...
Received an update from the publisher!
Received an update from the publisher!
Received an update from the publisher!
Goodbye! I'm a ConcreteObserver2
Goodbye! I'm a ConcreteObserver3
Goodbye! I'm a ConcreteObserver4
Goodbye! I'm a Publisher
Goodbye! I'm a Mediator
*/

总结

观察者模式中,观察者与被观察者有着密切的联系,耦合度高;
为了解决这个问题,程序员们发明了订阅者发布者模式,在这个模式下,
订阅者与发布者没有直接关系,大大的降低了耦合。

上面是我自己简单的见解,下面来看看高级玩家是如何描述的:

观察者模式(Observer Pattern)是一种行为型设计模式,其中存在一个被观察者(也称为主题或可观察者)和多个观察者之间的关系。当被观察者的状态发生变化时,它会通知所有观察者,并调用相应的方法来处理这些变化。这种模式中,被观察者和观察者之间是直接关联的,因此耦合度较高。
订阅者-发布者模式(Pub-Sub Pattern)是一种消息传递模式,其中存在一个发布者和多个订阅者之间的关系。发布者负责发送消息,而订阅者则订阅感兴趣的消息并进行处理。在这种模式中,发布者和订阅者之间没有直接的关联,它们通过消息队列、事件总线等机制进行通信,从而降低了耦合度。
下面是观察者模式和订阅者-发布者模式的一些关键区别:
1.关系类型:观察者模式是一种对象之间的一对多关系,即一个被观察者可以有多个观察者。而订阅者-发布者模式是一种消息传递机制,发布者和订阅者之间没有直接关联。
2.耦合度:观察者模式中,被观察者需要维护一个观察者列表,并将通知直接发送给观察者。这导致了较高的耦合度。而在订阅者-发布者模式中,发布者不需要知道谁订阅了它的消息,也无需维护订阅者列表,只需将消息发布到消息队列或事件总线中即可。
3.灵活性:由于观察者模式中被观察者和观察者之间的直接联系,可能会导致紧密耦合的设计。而在订阅者-发布者模式中,发布者和订阅者之间解耦,发布者和订阅者的数量和类型可以更加灵活地变化。
总的来说,订阅者-发布者模式通过引入一个中介(如消息队列、事件总线)来降低组件之间的耦合度,使系统更加灵活和可扩展。这种模式在处理大规模分布式系统、异步通信等方面非常有用。然而,在某些情况下,观察者模式仍然是一个简单而有效的解决方案,特别是当只需要维护少量对象之间的关系时。

知识补充:

#include <iostream>using namespace std;class A
{
public:A(){cout << "A" << endl;}private:
};int main(int argc, char **argv)
{A a;//调用构造函数A *a2;//不调用构造函数,仅仅是个指针而已A *a3 = new A();//调用构造函数return 0;
}
/*
A
A
*/

相关文章:

观察者模式、订阅者发布者模式、vtk中的观察者模式

文章目录 什么是观察者模式vtk是如何实现的观察者模式.AddObserver什么时候使用观察者模式&#xff1f;什么使用订阅发布者模式?观察者模式的实现订阅发布者的实现总结知识补充: 什么是观察者模式 用于在对象之间建立一对多的依赖关系&#xff0c;当一个对象的状态发生变化时…...

关于element-ui中,页面上有多个el-table并通过v-if、v-else等控制是否显示时,type=selection勾选框失效或不显示的问题

刚开始是勾选框那一列直接空了什么都不显示&#xff0c;搜索了一下说是给el-table标签增加id&#xff0c;加了之后是显示了&#xff0c;但是点击任何选框都会直接取消全部选中效果&#xff0c;翻了半天源码也没发现到底是哪里事件冲突了还是怎么回事&#xff0c;烦了&#xff0…...

Stewart六自由度正解、逆解计算-C#和Matlab程序

目录 一、Stewart并联六自由度正解计算 &#xff08;一&#xff09;概况 &#xff08;二&#xff09;Matlab正解计算 1、参考程序一 2、参考程序二 &#xff08;三&#xff09;C#程序正解计算 1、工程下载链接 2、正解运行计算 &#xff08;四&#xff09;正程…...

C语言 驼峰命名法和下划线命名法

在C语言中&#xff0c;变量命名遵循以下规则&#xff1a; 变量名只能由字母、数字和下划线组成。变量名必须以字母或下划线开头。变量名不能使用C语言中的关键字。变量名中不能出现连续的两个下划线。变量名区分大小写&#xff0c;例如&#xff0c;count和Count被视为两个不同…...

大数据学习(8)-hive压缩

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博>主哦&#x…...

[sqoop]hive导入mysql,其中mysql的列存在默认值列

一、思路 直接在hive表中去掉有默认值的了列&#xff0c;在sqoop导入时,指定非默认值列即可&#xff0c; 二、具体 mysql的表 hive的表 create table dwd.dwd_hk_rcp_literature(id string,literature_no string,authors string,article_title string,source_title string…...

Stream流中的常用方法(forEach,filter,map,count,limit,skip,concat)和Stream流的特点

1、forEach方法 该方法接收一个Consumer接口是一个 消费型 的函数式接口&#xff0c;可以传递Lambda表达式&#xff0c;消费数据用来遍历流中的数据&#xff0c;是一个 终结 方法&#xff0c;遍历 之后就不能继续调用Stream流中的其他方法 package com.csdn.stream; import jav…...

2023大联盟2比赛总结

比赛链接 反思 T1 奇怪的贪心和构造题一直是我的软肋部分 T2 简单题 T3 也不难 T4 套路没学过&#xff0c;感觉还是太菜了 题解 A 考虑先给图随便染色&#xff0c;然后调整 因为每个点的度数为 3 3 3&#xff0c;所以如果有 x → u → v x\to u\to v x→u→v 的颜…...

Flutter笔记:电商中文货币显示插件Money Display

Flutter笔记 电商中文货币显示插件 Money Display 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/1338…...

腾讯云上创建 对象存储cos

1. 登录腾讯云, 找到对象存储cos 2. 创建存储桶 3. 获取4个配置参数 桶名称 / 地域secretId / secretKey...

微信小程序生成海报

效果: js1: const cloudHelper = require(../../../helper/cloud_helper.js);async function config1({cover,title,desc,qr,bg = }) {var qr1 ="images/qr.png"var qr2 ="https://636c-cloud1-0gu29f2j63906b7e-1319556650.tcb.qcloud.la/activitycomm/setu…...

stm32学习笔记:EXIT中断

1、中断系统 中断系统是管理和执行中断的逻辑结构&#xff0c;外部中断是众多能产生中断的外设之一。 1.中断&#xff1a; 在主程序运行过程中&#xff0c;出现了特定的中断触发条件 (中断源&#xff0c;如对于外部中断来说可以是引脚发生了电平跳变&#xff0c;对于定时器来…...

css 块元素、行内元素、行内块元素相互转换

在HTML和CSS中&#xff0c;元素可以分为三类&#xff1a;块级元素&#xff08;Block-level Elements&#xff09;、内联元素&#xff08;Inline Elements&#xff09;和内联块级元素&#xff08;Inline-block Elements&#xff09;。 块级元素&#xff08;Block-level Elements…...

【JUC】多线程基础概述

文章目录 1. 一锁二并三程2. 用户线程和守护线程 1. 一锁二并三程 一锁&#xff1a;synchronized 二并: 并发&#xff1a;一台处理器“同时”处理多个任务&#xff0c;同一时刻只有一个事件发生并行&#xff1a;多台处理器同时处理多个任务&#xff0c;同一时刻多个处理器分…...

Git 回退代码的两种方法对比

Git 回退代码版本 在项目的开发中&#xff0c;有时候还是会出现&#xff0c;一些误提交了一些代码&#xff0c;这时候就会想撤回提交的代码&#xff0c;在Git中有两种方法可以使用&#xff0c;现在通过对比方法比较这两种方法的区别&#xff0c;分别适用于哪些情况&#xff1f…...

Avalonia常用小控件Charts

1.项目下载地址&#xff1a;https://gitee.com/confusedkitten/avalonia-demo 2.UI库Semi.Avalonia&#xff0c;项目地址 https://github.com/irihitech/Semi.Avalonia 3.Charts库&#xff0c;LiveChartsCore.SkiaSharpView.Avalonia&#xff0c;Nuget获取只有预览库&#x…...

【Hugging Face】管理 huggingface_hub 缓存系统

摘要 这篇文档介绍了Hugging Face Hub的缓存系统。该系统旨在提供一个中央缓存,以便不同版本的文件可以被下载和缓存。缓存系统将文件组织成模型、数据集和空间等不同的目录,每个目录包含特定类型的文件。系统确保如果文件已经下载并更新,除非明确要求,否则不会再次下载。…...

Python学习基础笔记六十六——对象的方法

我们已经学习到的对象类型&#xff1a; 整数类型的对象 字符串类型的对象 列表类型的对象 元组类型的对象 对象通常都有属于自己的方法&#xff08;method&#xff09; 调用对象的方法和调用函数差不多&#xff0c;只要在前面加上所属对象的一个点。 var1 [1, 2, 3,4, 5,…...

建立一个新的高阶数学教授模式,知其然,知其用,知其之所以然,知其所以然

1. 传统常用的模式 概念&#xff0c;性质&#xff0c;定理&#xff0c;定理证明&#xff0c;定理应用&#xff1b; 这个学习模式挺好的&#xff0c;但是定理证明过程往往很冗长&#xff0c;而且不易记忆&#xff0c;也就是说&#xff0c;即使推导了定理&#xff0c;初学者也记…...

AtCoder ABC324G 启发式合并

题意 传送门 AtCoder ABC324G Generate Arrays 题解 逆则操作顺序考虑&#xff0c;可以看作至多 n n n 个联通分量不断合并的过程&#xff0c;此时使用启发式合并&#xff0c;即规模较小的连通分量向规模较大的连通分量合并&#xff0c;以单个元素合并为基本运算&#xff0…...

SpringBootCMS漏洞复现分析

SpringBootCMS&#xff0c;极速开发&#xff0c;动态添加字段&#xff0c;自定义标签&#xff0c;动态创建数据库表并crud数据&#xff0c;数据库备份、还原&#xff0c;动态添加站点(多站点功能)&#xff0c;一键生成模板代码&#xff0c;让您轻松打造自己的独立网站&#xff…...

iOS- flutter flavor 多环境Configurations配置

一、点击PROJECT的Runner&#xff0c;选择Info选项&#xff0c;在Configurations下方的号添加不同环境的配置&#xff0c;如下图&#xff1a; 二、选择TAGETS的Runner项目&#xff0c;选择Build Settings选项&#xff0c;在输入框输入package&#xff0c;为不同环境配置相应的…...

【PyTorchTensorBoard实战】GPU与CPU的计算速度对比(附代码)

0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自己学习的理解&#xff0c;虽然参考了他人的宝贵见解&#xff0c;但是内容可能存在不准确的地方。如果发现文中错误&#xff0c;希望批评指正&#xff0c;共同进步。 本文基于PyTorch通过tensor点积所需要的时…...

npm 常用指令总结

1. 初始化包 一个存放了代码的文件夹,如果里面有 package.json 文件,则可以把这个文件夹称之为包。 npm init -y 注意: 由于包名不能有中文,不能有大写,不能和未来要下载的包重名. 所以我们快速初始化包时,我们的文件夹也不能违反前面说的规则.(因为默认会将文件夹的名称,作…...

布朗大学发现GPT-4存在新问题,可通过非常见语言绕过限制

&#x1f989; AI新闻 &#x1f680; 布朗大学发现GPT-4存在新漏洞&#xff0c;可通过非常见语言绕过限制 摘要&#xff1a;布朗大学计算机科学研究人员发现了OpenAI的GPT-4存在新漏洞&#xff0c;利用不太常见的语言如祖鲁语和盖尔语可以绕过各种限制。研究人员测试了GPT-4对…...

ESP32网络编程-TCP客户端数据传输

TCP客户端数据传输 文章目录 TCP客户端数据传输1、IP/TCP简单介绍2、软件准备3、硬件准备4、TCP客户端实现本文将详细介绍在Arduino开发环境中,实现一个ESP32 TCP客户端,从而达到与TCP服务器数据交换的目标。 1、IP/TCP简单介绍 Internet 协议(IP)是 Internet 的地址系统,…...

微信小程序入门级

目录 一.什么是小程序&#xff1f; 二.小程序可以干什么&#xff1f; 三.入门使用 3.1. 注册 3.2. 安装 3.3.创建项目 3.4.项目结构 3.5.应用 好啦今天就到这里了&#xff0c;希望能帮到你哦&#xff01;&#xff01;&#xff01; 一.什么是小程序&#xff1f; 微信小程…...

博客文档续更(二)

十五、博客前台模块-个人信息 1. 接口分析 进入个人中心的时候需要能够查看当前用户信息。请求不需要参数 请求方式 请求地址 请求头 GET /user/userInfo 需要token请求头 响应格式 {"code":200,"data":{"avatar":"头像的网络地址…...

Centos切换yum源

Centos切换yum源 常用命令 #查看内核/操作系统/CPU信息 uname -a #查看yum源 yum list repolist all切换步骤 1.备份yum源文件 cp -a /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak2.下载新的CentOS-Base.repo文件到/etc/yum.repos.d/目录下 …...

milvus和相似度检索

流程 milvus的使用流程是 创建collection -> 创建partition -> 创建索引(如果需要检索) -> 插入数据 -> 检索 这里以Python为例, 使用的milvus版本为2.3.x 首先按照库&#xff0c; python3 -m pip install pymilvus Connect from pymilvus import connections c…...