设计模式学习(二)-- 观察者模式 Observer Pattern

本文介绍观察者模式的基本概念,通过示例代码展示了如何利用Subject和Observer接口实现对象间的一对多依赖关系,使得主题状态发生变化时能自动通知所有观察者进行更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

观察者模式:定义了对象之间的一对多依赖,这样当一个对象状态改变的时候,它的所有依赖者都会收到通知并自动更新。

设计原则:为了交互对象之间的松耦合设计而努力。
松耦合的设计让对象之间的依赖降到最低,这样便于建立更加有弹性的系统,应对变化。

实现观察者模式的方法不止一种,但是包含Subject和Observer接口的设计实现最常见。

主题只需要知道观察者实现了观察者接口Observer,不需要知道观察者的具体类是谁,做了什么。主题唯一依赖的是一个实现了观察者Observer接口的对象列表,可以随时增加,删除观察者,并方便地通知所有列表中的观察者。
观察者只需要持有一个主题的对象,用于注册成为主题的观察者,这样就可以接受到主题状态改变的通知。

观察者模式类图
这里写图片描述

主题是拥有数据或者状态的对象,观察者依赖主题来获取数据或者状态的改变。一个主题可以有多个观察者依赖它。主题负责在数据或者状态改变的时候,将改变通知所有依赖它的观察者。观察者必须注册具体主题,以便接受更新。

代码实现

/**
 *
 * @author Yves
 */
public interface Subject{
        public void Register(Observer o);
        public void Remove(Observer o);
        public void NotifyObservers();
}

这是主题接口,对象使用此接口注册为观察者,或者把自己从观察者中删除。实现此接口的具体主题还必须实现NotifyObservers()方法用于在状态改变时通知所有的观察者。

class MySubject implements Subject {

    private String name;
    private int age;
    //observers list
    private ArrayList observers;   

    public MySubject() {
        //create observers list in the Contruct method.
        observers = new ArrayList();
    }

    @Override
    public void Register(Observer o) {
        observers.add(o);
    }

    @Override
    public void Remove(Observer o) {
        if (observers != null && !observers.isEmpty() && observers.contains(o)) {
            observers.remove(o);
        }
    }

    @Override
    public void NotifyObservers() {
        for (Object observer : observers) {
            Observer ob = (Observer) observer;
            ob.Update(name, age);
        }
    }

    public void ChangeDate(String name, int age) {
        this.SetName(name);
        this.SetAge(age);
        //notify all observers
        this.NotifyObservers();
    }

    public void SetName(String name) {
        this.name = name;
    }

    public void SetAge(int age) {
        this.age = age;
    }
}

具体主题类实现主题接口Subject,提供注册和删除观察者的方法,以及状态改变时通知所有观察者的方法。此处具体主题类维护一个ArrayList observers用来记录所有注册的观察者,以便实现注册、删除和通知观察者的方法。此外,具体主题类是拥有数据的对象,提供设置和获取这些数据的方法。ChangeDate(String name, int age)方法改变数据状态并且调用NotifyObservers()通知该主题维护的所有观察者。NotifyObservers()会调用每个观察者的Update()方法来实现数据状态改变的通知。

/**
 *
 * @author Yves
 */
 public interface Observer{
        public void Update(String name, int age);
 }

所有潜在观察者必须实现观察者接口,这个接口只有一个Update()方法,当主题状态改变时它被调用。

class ObserverA implements Observer {

    private String name;
    private int age;
    private MySubject mySubject;

    public ObserverA(MySubject mySubject) {
        this.mySubject = mySubject;
        //Register this observer to the observer list of Subject object.
        this.mySubject.Register(this);
    }

    @Override
    public void Update(String name, int age) {
        this.name = name;
        this.age = age;

        this.Display();
    }

    public void Display() {
        System.out.println("User name is: " + name + ", User age is: " + age);
    }

}

具体观察者实现观察者接口Observer,实现Update方法用于在主题的数据状态改变时更新这些数据状态。具体观察者必须注册主题,才能接收主题的更新通知。此处观察者持有一个具体主题的对象MySubject mySubject,在构造函数里面注册成为MySubject主题的观察者。

public class ObserverPattern {

    public static void main(String args[]){
        MySubject mys = new MySubject();
        ObserverA oba = new ObserverA(mys);
        //register an observer, THIS ACTIION is better done in the Observer class.
        //mys.Register(oba);
        //data change in MySubject, will notify all observers
        mys.ChangeDate("Yves", 18);
        //observers show the data
        oba.Display();
    }
}

注意:代码的实现不能依赖于观察者被通知的次序。因为一旦主题/观察者的实现改变了,通知的次序就会改变,依赖于某一特定实现的通知次序,是错误的。

Java API 内置观察者模式:java.util.Observable类和java.util.Observer为开发者接口提供了观察者模式。Observable类就是主题,具体的主题类需要继承Observable类。

由于Observable是一个类,所以具体主题就不能同时拥有Observable类和另一个超类的行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值