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

news2024/9/20 9:39:13

简介:

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

在观察者模式中,有以下几个核心组成部分:
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.coloradmin.cn/o/1123185.html

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

相关文章

c++ json 库的调用报错 “value, object or array expected“

表示输入的json 文件&#xff0c;写的格式有点不正确例如 双引号 逗号 字符串 列表等 aa.json 出现了一些问题&#xff0c;不是代码问题

Kubernetes概述及其组件/核心组件

Kubernetes 概述&#xff1a; 1、K8S 是什么&#xff1f; K8S 的全称为 Kubernetes (K12345678S)&#xff0c;PS&#xff1a;“嘛&#xff0c;写全称也太累了吧&#xff0c;不如整个缩写”。 作用&#xff1a; 用于自动部署、扩展和管理“容器化&#xff08;containerized&…

文章发表丨求臻医学发布病理AI模型,实现肿瘤精准分型

近日&#xff0c;求臻医学科研团队研发一款基于数字病理图像的肿瘤分型深度学习模型—TMG(The Transformer-based Multiple instance learning with Global average pooling)。该模型可有效消除对病理图像细粒度标记的依赖&#xff0c;实现高准确率的分型&#xff0c;将用于原发…

武汉凯迪正大—线圈匝间耐压测试仪

产品概述 KDYD2830绕组匝间冲击耐压试验仪适用于试验电压30kV及以下高压电机、中小型电机、直流电机的绕组匝间绝缘检测&#xff1b;也可用于变压器绕组、电器线圈绕组的匝间绝缘检测。因电机、变压器绕组由于绝缘结构和绝缘材料的不一致&#xff0c;特别是操作者工艺水平的不…

全志R128适配 ST7789v LCD

适配 ST7789v LCD R128 平台提供了 SPI DBI 的 SPI TFT 接口&#xff0c;具有如下特点&#xff1a; Supports DBI Type C 3 Line/4 Line Interface ModeSupports 2 Data Lane Interface ModeSupports data source from CPU or DMASupports RGB111/444/565/666/888 video form…

华为bug汇报:华为NPU竟成“遥遥领先”?

华为bug汇报&#xff1a;华为NPU竟成“遥遥领先”&#xff1f; 本文为我汇报在Ascend / pytorch 社区的一个bug&#xff0c;其中对NPU的实际算力进行了测试&#xff0c;并发现了华为NPU实际显存与销售宣传时存在着较大差差距的问题&#xff08;算力问题见问题一、显存问题见问…

数据分析和机器学习的11个高级可视化图表介绍

可视化是一种强大的工具&#xff0c;用于以直观和可理解的方式传达复杂的数据模式和关系。它们在数据分析中发挥着至关重要的作用&#xff0c;提供了通常难以从原始数据或传统数字表示中辨别出来的见解。 可视化对于理解复杂的数据模式和关系至关重要&#xff0c;我们将介绍11…

【软考】12.3 质量管理/风险管理

《质量管理》 影响质量&#xff1a;范围、进度、成本质量规划 ——> 质量保证&#xff08;阶段性评审&#xff09; ——> 质量控制&#xff08;实时监控&#xff09; 质量特性 功能性、可靠性、可用性、效率、可维护性、可移植性 McCall质量模型 产品修正、产品转移、…

CPU和GPU有什么区别?

CPU&#xff1a;叫做中央处理器&#xff08;central processing unit&#xff09;作为计算机系统的运算和控制核心&#xff0c;是信息处理、程序运行的最终执行单元。 GPU&#xff1a;叫做图形处理器。图形处理器&#xff08;英语&#xff1a;Graphics Processing Unit&#x…

快来get策略模式,告别编程困惑,轻松变身编程高手✨

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一…

【网络】网络编程套接字(二)

网络编程套接字 二 简单的TCP网络程序1、服务端创建套接字并绑定2、服务端监听2、服务端获取连接3、服务端处理请求4、客户端进行连接5、客户端发起通信6、通信测试 简单的TCP网络程序 TCP服务器创建套接字的做法与UDP服务器是基本一样的&#xff0c;但是TCP服务器会更加繁琐一…

独立产品灵感周刊 DecoHack #053 - 有意思的地图网站

本周刊记录有趣好玩的独立产品设计开发相关内容&#xff0c;每周发布&#xff0c;往期内容同样精彩&#xff0c;感兴趣的伙伴可以 点击订阅我的周刊。为保证每期都能收到&#xff0c;建议邮件订阅。欢迎通过 Twitter 私信推荐或投稿。 周刊继续发布 ❤️ &#x1f4bb; 产品推…

电脑屏幕模糊?这5个方法教你恢复清晰屏幕!

“我的电脑最近看着看着莫名就觉得好模糊&#xff0c;这到底是为什么呢&#xff1f;有什么方法可以解决电脑屏幕模糊的问题吗&#xff1f;” 使用电脑时&#xff0c;电脑屏幕是否清晰会很影响我们的使用体验感。如果电脑屏幕模糊&#xff0c;可能会给我们带来一种视觉上的不好体…

C#中的日期时间比较和格式化的方法

摘要&#xff1a;在C#中&#xff0c;日期和时间的比较以及格式化是常见的操作。了解如何正确比较和格式化日期和时间可以帮助我们更好地处理这些数据。本文将介绍C#中常用的日期时间比较方法&#xff08;CompareTo、Equals和比较运算符&#xff09;以及日期时间格式化方法&…

vue重修之路由【下】

文章目录 版权声明路由重定向、404&#xff0c;路由模式重定向404路由模式 声明式导航vue-routerrouter-link-active 和 router-link-exact-active定制router-link-active 和 router-link-exact-active跳转传参两种跳转传参总结 编程式导航两种语法路由传参path路径跳转传参nam…

Kafka3.x安装以及使用

一、Kafka下载 下载地址&#xff1a;https://kafka.apache.org/downloads 二、Kafka安装 因为选择下载的是 .zip 文件&#xff0c;直接跳过安装&#xff0c;一步到位。 选择在任一磁盘创建空文件夹&#xff08;不要使用中文路径&#xff09;&#xff0c;解压之后把文件夹内容剪…

10个最流行的开源机器视觉标注工具

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 我们知道寻找良好的图像标记和注释工具对于创建准确且有用的数据集的重要性。 随着图像注释空间的增长&#xff0c;我们看到开源工具的可用性激增&#xff0c;这些工具使任何人都可以免费标记他们的图像并从强大的功能中受…

这5种炫酷的动态图,都是用Python实现的!

数据可以帮助我们描述这个世界、阐释自己的想法和展示自己的成果&#xff0c;但如果只有单调乏味的文本和数字&#xff0c;我们却往往能难抓住观众的眼球。而很多时候&#xff0c;一张漂亮的可视化图表就足以胜过千言万语。本文将介绍 5 种基于 Plotly 的可视化方法&#xff0c…

IP地址SSL证书 IP证书

在许多企业用例中&#xff0c;公司需要SSL证书作为IP地址。公司使用IP地址通过Internet访问各种类型的应用程序。 公网IP地址的SSL证书&#xff1a; 内部IP&#xff08;也称为私有IP&#xff09;是IANA设置为保存的IPv4或IPv6地址&#xff0c;例如&#xff1a; RFC 1918范围内…

编译原理如何写出不带回溯的递归子程序?

递归子程序 使用不带回溯的递归子程序解析文法是预测性语法分析的基础&#xff0c;这通常需要该文法是LL(1)文法。每个非终结符对应一个递归子程序&#xff0c;并使用当前的输入符号和FIRST集合来决定调用哪个产生式。 让我们以一个简单的文法为例&#xff1a; 对于此文法&am…