Java设计模式之观察者模式

发布于:2025-03-24 ⋅ 阅读:(32) ⋅ 点赞:(0)

概念和作用

观察者模式(Observer Pattern)是一种软件设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式的主要作用是实现对象之间的动态耦合,让一个对象的改变能够自动通知并更新其他相关对象。这种模式在需要维护一致性和同步性的地方非常有用。

使用场景

1.当一个对象的改变需要同时改变其他对象时。

2.当一个抽象模型有两个方面,其中一个方面依赖于另一方面时。

3.当一个对象需要通知其他对象,但又不知道具体是哪些对象时。

实现方式

在Java中,可以通过实现java.util.Observer接口和java.util.Observable类来使用观察者模式。或者,也可以通过自定义接口来实现。

示例

假设有一个Person类,当人的名字改变时,需要通知相关的证件对象(如身份证、户口本、学生卡等)进行更新。

1.被观察者接口

// 被观察者接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String name);
}

2.观察者接口

// 观察者接口
interface Observer {
    void update(String name);
}

3.具体的被观察者(人)

// 具体的被观察者(人)
class Person implements Subject {
    private String name;
    private List<Observer> observers;

    public Person(String name) {
        this.name = name;
        this.observers = new ArrayList<>();
    }

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

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

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

    public void setName(String newName) {
        this.name = newName;
        notifyObservers(newName);
    }
}

4.身份证

// 具体的观察者(身份证)
class IDCard implements Observer {
    @Override
    public void update(String name) {
        System.out.println("身份证更新:名字已改为 " + name);
    }
}

5.户口本

// 具体的观察者(户口本)
class HouseholdRegister implements Observer {
    @Override
    public void update(String name) {
        System.out.println("户口本更新:名字已改为 " + name);
    }
}

6.学生卡

// 具体的观察者(学生卡)
class StudentCard implements Observer {
    @Override
    public void update(String name) {
        System.out.println("学生卡更新:名字已改为 " + name);
    }
}

7.测试类

// 测试类
public class Main {
    public static void main(String[] args) {
        Person person = new Person("张三");
        IDCard idCard = new IDCard();
        HouseholdRegister householdRegister = new HouseholdRegister();
        StudentCard studentCard = new StudentCard();

        person.registerObserver(idCard);
        person.registerObserver(householdRegister);
        person.registerObserver(studentCard);

        person.setName("李四");
    }
}

控制台输出:

身份证更新:名字已改为 李四
户口本更新:名字已改为 李四
学生卡更新:名字已改为 李四

优缺点

优点

1.松耦合:观察者和被观察者之间是松耦合的,可以独立地改变和复用。

2.广播通信:被观察者可以向所有注册的观察者发送通知,实现一对多的广播通信。

3.动态扩展:可以动态地增加或减少观察者,而不需要修改主体类的代码。

缺点

1.依赖关系复杂:被观察者和观察者之间的依赖关系可能会变得复杂,难以维护。

2.通知顺序问题:观察者无法确定被观察者状态更新的顺序。

3.线程安全问题:在Java的内置观察者模式中,Observable类和Observer接口没有考虑线程安全问题,需要开发者自己处理。

不使用观察者模式的实现

如果不使用观察者模式,可以手动维护一个观察者列表,并在被观察者状态改变时,遍历列表并调用每个观察者的更新方法。例如:

1.被观察者(人)

class Person {
    private String name;
    private List<Runnable> updaters = new ArrayList<>();

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

    public void addUpdater(Runnable updater) {
        updaters.add(updater);
    }

    public void removeUpdater(Runnable updater) {
        updaters.remove(updater);
    }

    public void setName(String newName) {
        this.name = newName;
        for (Runnable updater : updaters) {
            updater.run();
        }
    }
}

2.身份证

class IDCard {
    private Person person;

    public IDCard(Person person) {
        this.person = person;
        person.addUpdater(() -> System.out.println("身份证更新:名字已改为 " + person.name));
    }
}

3.户口本

class HouseholdRegister {
    private Person person;

    public HouseholdRegister(Person person) {
        this.person = person;
        person.addUpdater(() -> System.out.println("户口本更新:名字已改为 " + person.name));
    }
}

4.学生卡

class StudentCard {
    private Person person;

    public StudentCard(Person person) {
        this.person = person;
        person.addUpdater(() -> System.out.println("学生卡更新:名字已改为 " + person.name));
    }
}

5.测试类

public class Main {
    public static void main(String[] args) {
        Person person = new Person("张三");
        new IDCard(person);
        new HouseholdRegister(person);
        new StudentCard(person);

        person.setName("李四");
    }
}

这种方式虽然也能实现类似的效果,但不如观察者模式通用和灵活,且需要手动管理观察者的注册和通知逻辑。


网站公告

今日签到

点亮在社区的每一天
去签到