设计模式:观察者模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《命令模式》                                                                    下一篇《策略模式》

简介:

观察者模式,它是一种行为型设计模式,它允许一个对象自动通知其依赖者(观察者)状态的变化。当被观察者的状态发生改变时,它会通知所有的观察者对象,使他们能够及时做出响应。在观察者模式中,被观察者和观察者对象之间不需要知道对方的具体实现,只需要知道对方的接口,从而避免了紧耦合的关系。

在观察者模式中,有以下几个核心组成部分:
1、被观察者(Subject):它是一个抽象类或接口,维护一个观察者对象的列表,并定义了注册和删除观察者对象的方法。当被观察者的状态发生变化时,它负责通知所有已注册的观察者对象。
2、具体被观察者(ConcreteSubject):它是被观察者的具体实现,它维护一个状态,并定义了存储状态的方法。当它的状态发生变化时,它会通知所有已注册的观察者对象。
3、观察者(Observer):它是一个抽象类或接口,定义了更新方法以响应被观察者的状态变化。
4、具体观察者(ConcreteObserver):它是观察者的具体实现,实现了更新方法以响应被观察者的状态变化,并执行一些具体的业务逻辑处理。

在观察者模式中,被观察者和观察者之间形成了一种“一对多”的关系,当被观察者的状态发生变化时,所有注册的观察者都会得到通知并做出相应的响应。这种设计模式使得观察者与被观察者之间的耦合度降低,符合开闭原则,可以动态地增加或者删除观察者对象。然而,也需要注意避免出现循环依赖的问题,并确保在适当的时候移除观察者对象,避免内存泄漏的问题。

观察者模式的使用场景:
1、关联行为场景:观察者模式适用于建立一套触发机制的场景,例如用户关注某个商品的价格,当商品降价时进行通知,这样用户和商品产生了关联,触发机制就是商品降价。
2、事件处理系统:观察者模式可以用于实现事件处理系统,例如在购物网站中,多个用户关注某商品后,当商品降价时,就会自动通知关注该商品的用户。

总的来说,观察者模式适用于需要实现一对多的依赖关系,并且需要在对象状态改变时自动通知所有依赖者的场景。

观察者模式的创建步骤:
1、创建被观察者(Watched)类,该类通常包含一个观察者列表,以及一个用于添加、删除和通知观察者的方法。
2、创建观察者(Watcher)类,该类通常包含一个更新方法,用于在被观察者状态发生改变时更新自身状态。
3、在被观察者类中添加注册和注销观察者的方法,以便于添加和删除观察者对象。
4、在被观察者类中实现通知观察者的方法,以便于在状态发生改变时通知所有观察者对象。
5、创建具体被观察者(ConcreteWatched)类,该类继承自被观察者类,并实现具体的业务逻辑。
6、创建具体观察者(ConcreteWatcher)类,该类继承自观察者类,并实现具体的业务逻辑。
7、将具体被观察者和具体观察者对象进行组合,以便于在被观察者状态发生改变时通知所有观察者对象。

以上是观察者模式的基本创建步骤,需要注意的是,在实际应用中可能需要根据具体情况进行调整和优化。

观察者模式的优点,主要包括:
1、实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。
2、在观察目标和观察者之间建立一个抽象的耦合,观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
3、支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
4、符合“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。

观察者模式的缺点,主要包括:
1、如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

因此,在使用观察者模式时需要注意以上问题,避免出现不必要的缺陷。


示例:


一、C#观察者模式

以下是一个示例,展示了如何在C#中实现观察者模式:

//首先,定义一个被观察者接口:
public interface ISubject  
{  void Register(IObserver observer);  void Remove(IObserver observer);  void Notify();  
}
//然后,定义一个具体被观察者类:
public class ConcreteSubject : ISubject  
{  private List<IObserver> observers;  private string state;  public ConcreteSubject()  {  observers = new List<IObserver>();  }  public void Register(IObserver observer)  {  observers.Add(observer);  }  public void Remove(IObserver observer)  {  observers.Remove(observer);  }  public void Notify()  {  foreach (var observer in observers)  {  observer.Update(state);  }  }  public void SetState(string state)  {  this.state = state;  Notify();  }  
}
//接下来,定义一个观察者接口:
public interface IObserver  
{  void Update(string state);  
}
//最后,定义一个具体观察者类:
public class ConcreteObserver : IObserver  
{  private string name;  public ConcreteObserver(string name)  {  this.name = name;  }  public void Update(string state)   {   Console.WriteLine("{0} received update and the new state is {1}", name, state);   }   
}   
//接下来,可以创建一个具体的被观察者和多个具体观察者,并实现它们之间的交互:
public static void Main(string[] args){ISubject subject = new ConcreteSubject(); IObserver observer1 = new ConcreteObserver("Observer 1");IObserver observer2 = new ConcreteObserver("Observer 2"); IObserver observer3 = new ConcreteObserver("Observer 3"); subject.Register(observer1); subject.Register(observer2); subject.Register(observer3); subject.SetState("New State"); 
} 

在这个示例中,我们创建了一个被观察者对象subject和一个观察者对象observer1、observer2和observer3。我们将这些观察者对象注册到被观察者对象subject中,然后调用subject的SetState方法来改变其状态。当状态发生变化时,所有注册的观察者都会自动收到通知并执行Update方法。
在这个例子中,我们只是简单地打印出每个观察者的名称和新的状态。你可以根据自己的需求扩展这个示例。

二、java观察者模式

观察者模式通常通过以下方式实现:

public interface Subject {  void register(Observer observer);  void remove(Observer observer);  void notifyObservers(String message);  
}
public class ConcreteSubject implements Subject {  private List<Observer> observers;  private String message;  public ConcreteSubject() {  observers = new ArrayList<>();  }  @Override  public void register(Observer observer) {  observers.add(observer);  }  @Override  public void remove(Observer observer) {  observers.remove(observer);  }  @Override  public void notifyObservers(String message) {  for (Observer observer : observers) {  observer.update(message);  }  }  public void setMessage(String message) {  this.message = message;  notifyObservers(message);  }  
} public interface Observer {  void update(String message);  
}
class ConcreteObserver implements Observer {  private String name;  public ConcreteObserver(String name) {  this.name = name;  }  @Override  public void update(String message) {  System.out.println(name + " received update with message: " + message);  }  
}  
public class Main {  public static void main(String[] args) {  Subject subject = new ConcreteSubject();  Observer observer1 = new ConcreteObserver("Observer 1");  Observer observer2 = new ConcreteObserver("Observer 2");  Observer observer3 = new ConcreteObserver("Observer 3");  subject.register(observer1);  subject.register(observer2);  subject.register(observer3);  subject.setMessage("Hello World!");  }  
}

三、javascript观察者模式

在JavaScript中实现观察者模式,通常需要定义一个被观察者(Subject)和一个或多个观察者(Observer)。被观察者维护一个观察者列表,并在状态发生变化时遍历这个列表并调用每个观察者的更新方法。

下面是一个简单的JavaScript观察者模式的代码示例:

class Subject {  constructor() {  this.observers = [];  }  subscribe(observer) {  this.observers.push(observer);  }  unsubscribe(observer) {  this.observers = this.observers.filter(obs => obs !== observer);  }  notify(message) {  this.observers.forEach(observer => observer.update(message));  }  
}  class Observer {  constructor(name) {  this.name = name;  }  update(message) {  console.log(`${this.name} received update with message: ${message}`);  }  
}  // 使用示例  
const subject = new Subject();  
const observer1 = new Observer("Observer 1");  
const observer2 = new Observer("Observer 2");  
const observer3 = new Observer("Observer 3");  
subject.subscribe(observer1);  
subject.subscribe(observer2);  
subject.subscribe(observer3);  
subject.notify("Hello World!");

四、C++观察者模式

以下是在C++中实现观察者模式:

//定义一个观察者接口
class Observer {  
public:  virtual void update(Subject* subject) = 0;  
};
//定义一个被观察者接口
class Subject {  
public:  virtual void registerObserver(Observer* observer) = 0;  virtual void removeObserver(Observer* observer) = 0;  virtual void notifyObservers() = 0;  
};
//创建一个具体被观察者类
class ConcreteSubject : public Subject {  
private:  std::vector<Observer*> observers;  public:  void registerObserver(Observer* observer) override {  observers.push_back(observer);  }  void removeObserver(Observer* observer) override {  for (auto it = observers.begin(); it != observers.end(); ++it) {  if (*it == observer) {  observers.erase(it);  break;  }  }  }  void notifyObservers() override {  for (auto observer : observers) {  observer->update(this);  }  }  
};
//创建一个具体观察者类
class ConcreteObserver : public Observer {  
private:  std::string name;  public:  ConcreteObserver(std::string name) : name(name) {}  void update(Subject* subject) override {  std::cout << name << " received update." << std::endl;  }  
};
//使用示例:
int main() {  ConcreteSubject subject;  ConcreteObserver observer1("Observer 1");  ConcreteObserver observer2("Observer 2");  ConcreteObserver observer3("Observer 3");  subject.registerObserver(&observer1);  subject.registerObserver(&observer2);  subject.registerObserver(&observer3);  subject.notifyObservers(); // 输出:Observer 1 received update. Observer 2 received update. Observer 3 received update.  subject.removeObserver(&observer2); // 删除一个观察者  subject.notifyObservers(); // 输出:Observer 1 received update. Observer 3 received update.  return 0;  
}

五、python观察者模式

在Python中实现观察者模式,通常需要定义一个被观察者类和一个或多个观察者类。被观察者类维护一个观察者列表,并在状态发生变化时遍历这个列表并调用每个观察者的更新方法。
以下是在python中实现观察者模式:

class Subject:  def __init__(self):  self._observers = []  def attach(self, observer):  self._observers.append(observer)  def detach(self, observer):  self._observers.remove(observer)  def notify(self, value=None):  for observer in self._observers:  observer.update(value)  class Observer:  def update(self, value):  pass  class ConcreteObserver(Observer):  def update(self, value):  print(f"Observer received update with value: {value}")  # 使用示例  
subject = Subject()  
observer1 = ConcreteObserver()  
observer2 = ConcreteObserver()  
observer3 = ConcreteObserver()  
subject.attach(observer1)  
subject.attach(observer2)  
subject.attach(observer3)  
subject.notify(100) # 输出:Observer received update with value: 100 Observer received update with value: 100 Observer received update with value: 100   
subject.detach(observer2) # 删除一个观察者  
subject.notify(200) # 输出:Observer received update with value: 200 Observer received update with value: 200

六、go观察者模式

以下是一个示例,展示了如何在go中实现观察者模式:

type Subject struct {  observers []Observer  
}  func (s *Subject) Attach(observer Observer) {  s.observers = append(s.observers, observer)  
}  func (s *Subject) Notify() {  for _, observer := range s.observers {  observer.Update()  }  
}  typeObserver interface {  Update()  
}  typeConcreteObserver struct {  name string  
}  func (o *ConcreteObserver) Update() {  fmt.Printf("Observer %s received update.\n", o.name)  
}

在这个示例中,我们定义了一个被观察者结构体Subject,它维护一个观察者列表observers。我们定义了一个Attach方法用于将一个观察者添加到观察者列表中,以及一个Notify方法用于遍历观察者列表并调用每个观察者的Update方法。我们定义了一个观察者接口Observer,它包含一个Update方法。最后,我们创建了一个具体观察者结构体ConcreteObserver,它实现了Observer接口的Update方法。在主函数中,我们创建了一个被观察者对象subject和一个具体观察者对象observer,并将它们分别添加到被观察者和观察者列表中。然后我们调用被观察者的Notify方法来通知所有注册的观察者状态变化。

七、PHP观察者模式

以下是一个示例,展示了如何在PHP中实现观察者模式:

//定义一个主题接口(Subject):
interface Subject {  public function attach(Observer $observer);  public function detach(Observer $observer);  public function notify(Observer $observer);  
}
//定义一个具体主题类(ConcreteSubject):
class ConcreteSubject implements Subject {  private $observers = [];  private $state;  public function attach(Observer $observer) {  $this->observers[] = $observer;  }  public function detach(Observer $observer) {  $index = array_search($observer, $this->observers);  if ($index !== false) {  unset($this->observers[$index]);  }  }  public function notify(Observer $observer) {  foreach ($this->observers as $observer) {  $observer->update($this->state);  }  }  public function setState($state) {  $this->state = $state;  $this->notify($this->observers);  }  
}
//定义一个观察者接口(Observer):
interface Observer {  public function update($state);  
}
//定义一个具体观察者类(ConcreteObserver):
class ConcreteObserver implements Observer {  private $name;  public function __construct($name) {  $this->name = $name;  }  public function update($state) {  echo "Observer {$this->name} received update with state: {$state}\n";  }  
}// 创建具体观察者对象  
$observer1 = new ConcreteObserver("Observer 1");  
$observer2 = new ConcreteObserver("Observer 2");  
$observer3 = new ConcreteObserver("Observer 3");  // 创建具体主题对象并附加观察者对象  
$subject = new ConcreteSubject();  
$subject->attach($observer1);  
$subject->attach($observer2);  
$subject->attach($observer3);  // 设置主题状态并通知观察者对象更新状态信息  
$subject->setState("new state");

  
《完结》

上一篇《命令模式》                                                                    下一篇《策略模式》

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

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

相关文章

Windows Server服务器下的Linux子系统

导读Windows、Linux看似死敌一对&#xff0c;但其实微软对于开源实业还是相当支持的&#xff0c;Windows 10系统内就首次内置了一个Linux子系统(Windows Subsystem for Linux/WSL)&#xff0c;允许开发者模拟Linux环境&#xff0c;而且有需要的可以直接从Windows应用商店下载SU…

顺序栈的实现----数据结构

栈的概念 对于栈&#xff08;Stack&#xff09;&#xff0c;后进先出&#xff08;Last In First Out&#xff0c;LIFO&#xff09;&#xff0c;栈也是一种线性表&#xff0c;只不过是一种操作受限的线性表&#xff0c;只能在一端操作&#xff0c;也就是不允许在中间进行查找、…

华为云全新上线Serverless应用中心,支持一键构建文生图应用

近日&#xff0c;华为云全新上线Serverless应用中心&#xff0c;提供了大量应用模板&#xff0c;让用户能够一键部署函数和周边依赖资源&#xff0c;节省部署时间&#xff0c;快速上手将应用部署到华为云函数计算FunctionGraph&#xff0c;并一键开通周边依赖资源。 本次Serve…

搭建一个windows的DevOps环境记录

边搭建边记录&#xff0c;整个DevOps环境的搭建可能会很久。。。 一、安装Jenkins&#xff1a; 参考&#xff1a;Jenkins基础篇--windows安装Jenkins-CSDN博客 注意上面选择JDK的路径&#xff0c;选择到安装目录&#xff0c;该目录并不一定要在path中配置了&#xff08;就是…

Python中使用cv2.resize()函数批量自定义缩放图像尺寸

目录 常用插值缩放方法缩放示例代码总结 常用插值缩放方法 cv2.resize()函数中的interpolation参数指定了图像缩放时使用的插值方法。以下是常用的插值方法&#xff1a; cv2.INTER_NEAREST&#xff1a;最近邻插值。该方法通过选择最接近目标像素的原始像素来进行插值。它是最…

【Unity地编细节】为什么Unity笔刷在地形上面刷不出来

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

python+unittest+requests+HTMLRunner编写接口自动化测试集

问题描述&#xff1a; 搭建接口测试框架&#xff0c;执行用例请求多个不同请求方式的接口 实现步骤&#xff1a; ① 创建配置文件config.ini&#xff0c;写入部分公用参数&#xff0c;如接口的基本url、测试报告文件路径、测试数据文件路径等配置项 1 [DATABASE] 2 data_addre…

redis的key超时策略和key淘汰机制(面试题详解)

ChatGPT给出的回答&#xff1a; Redis中的Key超时策略和Key淘汰机制是为了有效管理内存和控制数据的生命周期。 Key超时策略&#xff1a;Redis可以为每个Key设置过期时间&#xff0c;一旦Key过期&#xff0c;它将自动从Redis中删除。可以使用EXPIRE命令为Key设置过期时间&…

【自然语言处理】理解词向量、CBOW与Skip-Gram模型

文章目录 一、词向量基础知识1.1 One-hot表示1.2 Distributed表示 二、word2vec基础知识2.1 CBOW和Skip-gram 三、基于Hierarchical Softmax的 CBOW 模型和 Skip-gram 模型3.1 CBOW 模型3.2 Skip-gram 模型 参考资料 由于计算机不能直接对各种字符进行运算&#xff0c;为此需要…

党建展馆vr仿真解说员具有高质量的表现力和互动性

随着虚拟数字人应用渐成趋势&#xff0c;以虚拟数字人为核心的营销远比其他更能加速品牌年轻化进程和认识&#xff0c;助力企业在激烈的市场竞争中脱颖而出&#xff0c;那么企业虚拟IP代言人解决了哪些痛点? 解决品牌与代言人之间的风险问题 传统代言人在代言品牌时&#xff0…

【C语言|关键字】C语言32个关键字详解(4)——其他(typedef、sizeof)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

vue面试题及答案【集合目录】

前言&#xff1a; 欢迎浏览和关注本专栏《 前端就业宝典 》&#xff0c; 不管是扭螺丝还是造火箭&#xff0c; 多学点知识总没错。 这个专栏是扭螺丝之上要造火箭级别的知识&#xff0c;会给前端工作学习的小伙伴带来意想不到的帮助。 本专栏将前端知识拆整为零&#xff0c;主要…

【技能树笔记】网络篇——练习题解析(九)

目录 前言 一、OSPF双栈 1.1 OSPFv3 LSA 1.2 OSPFv3 二、ISIS双栈 2.1 ISISv6 2.2 ISIS高级特性 三、BGP双栈 四、PIM双栈 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filot…

2023 10月最新Vmd 下载安装教程,WindowsLinux

文章目录 下载Vmdwindows版本安装LINUX版本安装 下载Vmd 谷歌搜索VMD 点击左下角download VMD 可选择对应版本 注&#xff1a;点击后会出现输入用户名和密码&#xff0c;由于我已注册&#xff0c;界面不见了&#xff0c;所以直接描述一下。 输入用户名和密码然后会出现让登记…

AI工具大爆发,写作工具选择谁?

AI在生活中的发挥的作用越来越明显&#xff0c;许多人也想使用AI工具来提高自己的工作效率又或者学习效率&#xff0c;那么作为AI小白的我们该怎么选择写作工具呢&#xff1f;跟着小编的脚步&#xff0c;接着往下阅读。 首先我们需要选择一个适合自己的AI工具以便开展后续工作…

HTML图像标签

html文件&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>图像标签学习</title> </head> <body> <img src"../resources/image/01.jpg" alt"小狗图…

玩转 MaxCompute SQL 训练营! 数据分析挖掘迅速出师

云布道师 用 MaxCompute 在数据里面挖呀挖呀挖&#xff0c;写花样的 sql 分析花样的数据&#xff01;云原生大数据计算服务 MaxCompute 是企业级 Serverless 智能数仓&#xff0c;向用户提供了完善的数据导入方案以及多种经典的分布式计算模型&#xff0c;能够更快速的解决用户…

多变量GARCH模型R代码实现

大家好&#xff0c;我是带我去滑雪&#xff01; 多变量GARCH&#xff08;Generalized Autoregressive Conditional Heteroskedasticity&#xff09;模型是一种用于建模多个时间序列变量之间的条件异方差性&#xff08;conditional heteroskedasticity&#xff09;的统计模型。它…

一文读懂:什么是块存储、文件存储、对象存储?

大家好&#xff0c;我是小学僧。 提到"存储"&#xff0c; 你首先想到的是这个&#xff1f; 还是这个&#xff1f; 也或者还有这个&#xff1f; 哈哈&#xff0c;没错&#xff0c;我们生活中已经离不开存储&#xff0c;视频、音乐、图片、文本、表格这样的数据文件都…

mac上mongodb 以及可视化工具 下载以及安装

简介 1. 下载 官网上的下载地址藏得非常深&#xff0c;不花老半天 根本找不到 下载地址 https://www.mongodb.com/try/download/community 目前最新社区版本7.0.2 下载链接 mac intel芯片 &#xff1a; https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-7.0.2.tgz ma…