概念和作用
观察者模式(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("李四");
}
}
这种方式虽然也能实现类似的效果,但不如观察者模式通用和灵活,且需要手动管理观察者的注册和通知逻辑。