观察者模式、订阅者发布者模式、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什么时候使用观察者模式?什么使用订阅发布者模式?观察者模式的实现订阅发布者的实现总结知识补充: 什么是观察者模式 用于在对象之间建立一对多的依赖关系,当一个对象的状态发生变化时…...
关于element-ui中,页面上有多个el-table并通过v-if、v-else等控制是否显示时,type=selection勾选框失效或不显示的问题
刚开始是勾选框那一列直接空了什么都不显示,搜索了一下说是给el-table标签增加id,加了之后是显示了,但是点击任何选框都会直接取消全部选中效果,翻了半天源码也没发现到底是哪里事件冲突了还是怎么回事,烦了࿰…...
Stewart六自由度正解、逆解计算-C#和Matlab程序
目录 一、Stewart并联六自由度正解计算 (一)概况 (二)Matlab正解计算 1、参考程序一 2、参考程序二 (三)C#程序正解计算 1、工程下载链接 2、正解运行计算 (四)正程…...
C语言 驼峰命名法和下划线命名法
在C语言中,变量命名遵循以下规则: 变量名只能由字母、数字和下划线组成。变量名必须以字母或下划线开头。变量名不能使用C语言中的关键字。变量名中不能出现连续的两个下划线。变量名区分大小写,例如,count和Count被视为两个不同…...
大数据学习(8)-hive压缩
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博>主哦&#x…...
[sqoop]hive导入mysql,其中mysql的列存在默认值列
一、思路 直接在hive表中去掉有默认值的了列,在sqoop导入时,指定非默认值列即可, 二、具体 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接口是一个 消费型 的函数式接口,可以传递Lambda表达式,消费数据用来遍历流中的数据,是一个 终结 方法,遍历 之后就不能继续调用Stream流中的其他方法 package com.csdn.stream; import jav…...
2023大联盟2比赛总结
比赛链接 反思 T1 奇怪的贪心和构造题一直是我的软肋部分 T2 简单题 T3 也不难 T4 套路没学过,感觉还是太菜了 题解 A 考虑先给图随便染色,然后调整 因为每个点的度数为 3 3 3,所以如果有 x → u → v x\to u\to v x→u→v 的颜…...
Flutter笔记:电商中文货币显示插件Money Display
Flutter笔记 电商中文货币显示插件 Money Display 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址: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、中断系统 中断系统是管理和执行中断的逻辑结构,外部中断是众多能产生中断的外设之一。 1.中断: 在主程序运行过程中,出现了特定的中断触发条件 (中断源,如对于外部中断来说可以是引脚发生了电平跳变,对于定时器来…...
css 块元素、行内元素、行内块元素相互转换
在HTML和CSS中,元素可以分为三类:块级元素(Block-level Elements)、内联元素(Inline Elements)和内联块级元素(Inline-block Elements)。 块级元素(Block-level Elements…...
【JUC】多线程基础概述
文章目录 1. 一锁二并三程2. 用户线程和守护线程 1. 一锁二并三程 一锁:synchronized 二并: 并发:一台处理器“同时”处理多个任务,同一时刻只有一个事件发生并行:多台处理器同时处理多个任务,同一时刻多个处理器分…...
Git 回退代码的两种方法对比
Git 回退代码版本 在项目的开发中,有时候还是会出现,一些误提交了一些代码,这时候就会想撤回提交的代码,在Git中有两种方法可以使用,现在通过对比方法比较这两种方法的区别,分别适用于哪些情况?…...
Avalonia常用小控件Charts
1.项目下载地址:https://gitee.com/confusedkitten/avalonia-demo 2.UI库Semi.Avalonia,项目地址 https://github.com/irihitech/Semi.Avalonia 3.Charts库,LiveChartsCore.SkiaSharpView.Avalonia,Nuget获取只有预览库&#x…...
【Hugging Face】管理 huggingface_hub 缓存系统
摘要 这篇文档介绍了Hugging Face Hub的缓存系统。该系统旨在提供一个中央缓存,以便不同版本的文件可以被下载和缓存。缓存系统将文件组织成模型、数据集和空间等不同的目录,每个目录包含特定类型的文件。系统确保如果文件已经下载并更新,除非明确要求,否则不会再次下载。…...
Python学习基础笔记六十六——对象的方法
我们已经学习到的对象类型: 整数类型的对象 字符串类型的对象 列表类型的对象 元组类型的对象 对象通常都有属于自己的方法(method) 调用对象的方法和调用函数差不多,只要在前面加上所属对象的一个点。 var1 [1, 2, 3,4, 5,…...
建立一个新的高阶数学教授模式,知其然,知其用,知其之所以然,知其所以然
1. 传统常用的模式 概念,性质,定理,定理证明,定理应用; 这个学习模式挺好的,但是定理证明过程往往很冗长,而且不易记忆,也就是说,即使推导了定理,初学者也记…...
AtCoder ABC324G 启发式合并
题意 传送门 AtCoder ABC324G Generate Arrays 题解 逆则操作顺序考虑,可以看作至多 n n n 个联通分量不断合并的过程,此时使用启发式合并,即规模较小的连通分量向规模较大的连通分量合并,以单个元素合并为基本运算࿰…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
