您现在的位置是:首页 >技术交流 >【设计模式】观察者模式篇网站首页技术交流

【设计模式】观察者模式篇

Point酱 2024-06-14 17:19:17
简介【设计模式】观察者模式篇

Observer Pattern

1、定义

观察者模式是一种设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生改变时,它的所有依赖对象都会收到通知并自动更新。

在观察者模式中,有两个主要角色:被观察者和观察者。被观察者维护了一个观察者列表,并提供了添加和删除观察者的方法。当被观察者的状态发生改变时,它会遍历观察者列表并调用每个观察者的更新方法,通知它们状态的改变。

观察者模式可以被应用于许多场景中,例如用户界面组件、事件处理等。它使得对象之间的耦合度降低,因为被观察者不需要知道观察者的具体实现,而只需要通知它们即可。同时,观察者模式也提高了代码的可维护性和可扩展性,因为可以方便地添加或移除观察者,而不需要修改被观察者的代码。

2、优缺点

优点:

  1. 松耦合性:观察者模式实现了松耦合,使得观察者和主题之间的依赖关系变得比较小,各自可以独立地进行扩展。
  2. 可重用性:观察者模式使得主题和观察者之间的关系可以被复用,不需要修改原有代码即可增加新的观察者。
  3. 支持广播通信:观察者模式支持广播通信,当主题对象发生改变时,会向所有的观察者发送通知,保证所有观察者对象的状态都是最新的。

缺点:

  1. 观察者过多导致性能问题:如果观察者数量过多或者观察者的处理时间过长,会降低系统的性能。
  2. 顺序执行问题:观察者模式中,各个观察者是按照添加的顺序执行的,如果观察者之间有依赖关系,可能会导致程序出现问题。
  3. 异常处理问题:如果一个观察者出现了异常,可能会影响整个系统的稳定性。

3、比喻了解

观察者模式可以通过生活中的例子来理解。

假设你是一位球迷,你想要及时了解你最喜欢的足球队的比赛成绩。于是你订阅了这个足球队的官方网站,并将其作为观察者。当这个足球队的比赛结果出来后,官方网站就会向你发送通知,告诉你比赛的结果。

在这个例子中,足球队就是主题对象,而球迷就是观察者。球迷可以随时取消订阅,也可以同时订阅多个足球队的官方网站,这就体现了观察者模式中的松耦合性和可重用性。同时,足球队可以向所有订阅者广播比赛结果,这就体现了观察者模式中的广播通信特性。

总的来说,观察者模式就是一个对象(即主题)发生变化时,其他对象(即观察者)能得到通知并自动更新,从而实现对象之间的松耦合、可重用性和广播通信等特性。

4、代码示例

import java.util.ArrayList;

interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}

interface Observer {
    void update(String message);
}

class NewsPaper implements Subject {
    private ArrayList<Observer> observers = new ArrayList<>();

    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void setNews(String news) {
        System.out.println("今日新闻:" + news);
        notifyObservers(news);
    }
}

class Reader implements Observer {
    private String name;

    public Reader(String name) {
        this.name = name;
    }

    public void update(String message) {
        System.out.println(name + "收到新闻:" + message);
    }
}

public class ObserverDemo {
    public static void main(String[] args) {
        NewsPaper newspaper = new NewsPaper();

        Reader reader1 = new Reader("小明");
        Reader reader2 = new Reader("小红");

        newspaper.registerObserver(reader1);
        newspaper.registerObserver(reader2);

        newspaper.setNews("中国女排夺冠了!");
        // 输出:
        // 今日新闻:中国女排夺冠了!
        // 小明收到新闻:中国女排夺冠了!
        // 小红收到新闻:中国女排夺冠了!
    }
}

在这个示例中,NewsPaper是主题接口,Reader是观察者接口。NewsPaper实现了主题接口,包含了注册、移除和通知观察者的方法。

Reader实现了观察者接口,包含了更新状态的方法。在main方法中,我们创建了一个NewsPaper对象和两个Reader对象,并将两个Reader对象注册到NewsPaper中。当NewsPaper的新闻发生改变时,它会通知所有的观察者,并调用它们的update方法。最终,输出结果表明两个Reader对象都收到了这条新闻。

class Subject {
  constructor() {
    this.observers = [];
  }

  registerObserver(observer) {
    this.observers.push(observer);
  }

  removeObserver(observer) {
    const index = this.observers.findIndex((o) => o === observer);
    this.observers.splice(index, 1);
  }

  notifyObservers(message) {
    for (const observer of this.observers) {
      observer.update(message);
    }
  }
}

class NewsPaper extends Subject {
  constructor() {
    super();
    this.news = "";
  }

  setNews(news) {
    console.log(`今日新闻:${news}`);
    this.news = news;
    this.notifyObservers(news);
  }
}

class Reader {
  constructor(name) {
    this.name = name;
  }

  update(message) {
    console.log(`${this.name}收到新闻:${message}`);
  }
}

const newspaper = new NewsPaper();

const reader1 = new Reader("小明");
const reader2 = new Reader("小红");

newspaper.registerObserver(reader1);
newspaper.registerObserver(reader2);

newspaper.setNews("中国女排夺冠了!");
// 输出:
// 今日新闻:中国女排夺冠了!
// 小明收到新闻:中国女排夺冠了!
// 小红收到新闻:中国女排夺冠了!

在这个示例中,Subject是主题类,包含了注册、移除和通知观察者的方法。NewsPaper继承自Subject,实现了设置新闻和记录新闻的功能。

Reader是观察者类,包含了更新状态的方法。在代码的最后,我们创建了一个NewsPaper对象和两个Reader对象,并将两个Reader对象注册到NewsPaper中。当NewsPaper的新闻发生改变时,它会通知所有的观察者,并调用它们的update方法。最终,输出结果表明两个Reader对象都收到了这条新闻。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。