1,通用写法
//抽象主题者
public interface ISubject<E> {
boolean attach(IObserver<E> observer);
boolean detach(IObserver<E> observer);
void notify(E event);
}
//具体主题者
public class ConcreteSubject<E> implements ISubject<E> {
private List<IObserver<E>> observers = new ArrayList<IObserver<E>>();
public boolean attach(IObserver<E> observer) {
return !this.observers.contains(observer) && this.observers.add(observer);
}
public boolean detach(IObserver<E> observer) {
return this.observers.remove(observer);
}
public void notify(E event) {
for (IObserver<E> observer : this.observers) {
observer.update(event);
}
}
}
//抽象观察者
public interface IObserver<E> {
void update(E event);
}
//具体观察者
public class ConcreteObserver<E> implements IObserver<E> {
public void update(E event) {
System.out.println("receive event: " + event);
}
}
public class Test {
public static void main(String[] args) {
// 被观察者
ISubject<String> observable = new ConcreteSubject<String>();
// 观察者
IObserver<String> observer = new ConcreteObserver<String>();
// 注册
observable.attach(observer);
// 通知
observable.notify("hello");
}
}
看一下类图:

抽象主题(subject):指被观察的对象(Observable)。该角色是一个抽象类或接口,定义了增加,删除,通知观察者的方法。
具体主题(ConcreteSubject):具体被观察者,当期内部状态变化时,会通知已注册的观察者。
抽象观察者(Observer):定义了相应通知的更新方法。
具体观察者(ConcreteObserver):在得到状态更新时,会自动做出响应。
下面举一个业务场景,主要是用到了jdk中的观察者的抽象
Observable和Observer都是JDK中的
public class GPer extends Observable {
private String name = "GPer生态圈";
private static final GPer gper = new GPer();
private GPer() {}
public static GPer getInstance(){
return gper;
}
public String getName() {
return name;
}
public void publishQuestion(Question question){
System.out.println(question.getUserName() + "在" + this.name + "上提交了一个问题。");
setChanged();
notifyObservers(question);
}
}
public class Teacher implements Observer {
private String name;
public Teacher(String name) {
this.name = name;
}
public void update(Observable o, Object arg) {
GPer gper = (GPer)o;
Question question = (Question)arg;
System.out.println("======================");
System.out.println(name + "老师,你好!\n" +
"您收到了一个来自" + gper.getName() + "的提问,希望您解答。问题内容如下:\n" +
question.getContent() + "\n" +
"提问者:" + question.getUserName());
}
}
@Data
public class Question {
private String userName;
private String content;
}
public class Test {
public static void main(String[] args) {
GPer gper = GPer.getInstance();
Teacher tom = new Teacher("Tom");
Teacher jerry = new Teacher("Jerry");
gper.addObserver(tom);
gper.addObserver(jerry);
//用户行为
Question question = new Question();
question.setUserName("张三");
question.setContent("观察者模式适用于哪些场景?");
gper.publishQuestion(question);
}
}
------------控制台打印如下-----------
张三在GPer生态圈上提交了一个问题。
======================
Jerry老师,你好!
您收到了一个来自GPer生态圈的提问,希望您解答。问题内容如下:
观察者模式适用于哪些场景?
提问者:张三
======================
Tom老师,你好!
您收到了一个来自GPer生态圈的提问,希望您解答。问题内容如下:
观察者模式适用于哪些场景?
提问者:张三
此示例的类图如下:

观察者模式优缺点:
优点:
1,观察者和被观察者是松耦合(抽象耦合)的,符合依赖倒置原则。
2,分离了表现层(观察者)和数据逻辑层(被观察者),并且建立一套触发机制,使得数据的变化可以影响到多个表现层上。
3,实现一对多的通讯机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。
缺点:
1,如果观察者数量过多,则事件通知耗时较长。
2,事件通知呈线性关系,如果一个观察者处理时间卡壳,会影响到后面的观察者接收到该事件。
3,如果观察者和被观察者存在循环依赖,则可能造成两者之间的循环调用,导致系统崩溃。