一、概述
观察者模式(Observer),又叫发布-订阅(Publish/Subscribe)模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某个主题对象,这个主题对象发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
二、UML图示
三、双向耦合编程实现
1、主题类
public abstract class Subject {
private List<Observer> observers = new ArrayList<>();
/**
* 增加观察者
* @param observer
*/
public void attach(Observer observer){
observers.add(observer);
}
/**
* 移除观察者
* @param observer
*/
public void detach(Observer observer){
observers.remove(observer);
}
/**
* 通知
*/
public void notifyObservers(){
for (Observer observer:observers) {
observer.update();
}
}
}
2、观察者
public abstract class Observer {
public abstract void update();
}
3、具体主题
public class ConcreteSubject extends Subject{
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
4、具体观察者
public class ConcreteObserver extends Observer {
private String name;
private String observerState;
private ConcreteSubject concreteSubject;
public ConcreteObserver(String name, ConcreteSubject concreteSubject) {
this.name = name;
this.concreteSubject = concreteSubject;
}
public ConcreteSubject getConcreteSubject() {
return concreteSubject;
}
public void setConcreteSubject(ConcreteSubject concreteSubject) {
this.concreteSubject = concreteSubject;
}
@Override
public void update() {
observerState = concreteSubject.getSubjectState();
System.out.println("观察者"+name+",新状态是:"+observerState);
}
}
5、测试类
public class Test {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
concreteSubject.attach(new ConcreteObserver("aa",concreteSubject));
concreteSubject.attach(new ConcreteObserver("bb",concreteSubject));
concreteSubject.attach(new ConcreteObserver("cc",concreteSubject));
concreteSubject.setSubjectState("ABC");
concreteSubject.notifyObservers();
}
}
输出:
观察者aa,新状态是:ABC
观察者bb,新状态是:ABC
观察者cc,新状态是:ABC
不难发现,上述代码存在几个严重问题:一是观察者与主题之间存在互相耦合;二是违背软件设计中的开发-封闭原则;三是违背软件设计中的依赖倒转原则,我们应该让程序都依赖抽象,而不是互相依赖。
四、解耦代码实现
1、主题接口
public interface Subject {
/**
* 增加观察者
* @param observer
*/
public void attach(Observer observer);
/**
* 移除观察者
* @param observer
*/
public void detach(Observer observer);
/**
* 通知
*/
public void notifyObservers();
}
2、观察者接口
public interface Observer {
void update(String message);
}
3、具体主题
public class ConcreteSubject implements Subject{
//注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
private List<Observer> list;
private String message;
public ConcreteSubject() {
list = new ArrayList<>();
}
@Override
public void attach(Observer observer) {
list.add(observer);
}
@Override
public void detach(Observer observer) {
list.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer o:list) {
o.update(message);
}
}
public void setInfomation(String s){
this.message = s;
System.out.println("服务器更新消息:"+s);
//通知观察者
notifyObservers();
}
}
4、具体观察者
public class ConcreteObserver implements Observer {
private String name;
private String message;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
System.out.println(this.name+"收到消息:"+this.message);
}
}
5、测试类
public class Test {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("aa");
Observer observer2= new ConcreteObserver("bb");
Observer observer3 = new ConcreteObserver("cc");
concreteSubject.attach(observer1);
concreteSubject.attach(observer2);
concreteSubject.attach(observer3);
concreteSubject.setInfomation("PHP是世界上最好的语言!");
}
}
输出:
服务器更新消息:PHP是世界上最好的语言!
aa收到消息:PHP是世界上最好的语言!
bb收到消息:PHP是世界上最好的语言!
cc收到消息:PHP是世界上最好的语言!