- 代码地址
- 简介
- 代码示例
简介https://gitee.com/nssnail/design-pattern/tree/master/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F
观察者模式(Observer Pattern ),又叫发布-订阅( Publish/Subscribe )模式、模型-视图( Model/View)模式、源-监听器(Source/Listener )模式或从属者( Dependents )模式。定义一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听,使得每当主题对象状态变化时,所有依赖于它的对象都会得到通知并被自动更新。属于行为型模式。
观察者模式的核心是将观察者与被观察者解耦,以类似于消息/广播发送的机制联动两者,使被观察者的变动能通知到感兴趣的观察者们,从而做出相应的响应。
观察者模式是一种对象行为型模式,其主要优点如下。
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
- 目标与观察者之间建立了一套触发机制。
它的主要缺点如下。
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
类图如下
实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。
模式的结构
观察者模式的主要角色如下。
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
代码示例简单来说其实就是广播模式,将消息分发给所有人
WeatherObservable.java
public interface WeatherObservable {
String getName();
void response(String message);
}
FJObservable.java
public class FJObservable implements WeatherObservable {
private final String NAME="福建气象站";
@Override
public String getName() {
return NAME;
}
public void response(String message) {
System.out.println("==================="+NAME+"收到气象信息===================");
System.out.println("气象信息:"+message+"n");
}
}
GDObservable.java
public class GDObservable implements WeatherObservable {
public final String NAME="广东气象站";
@Override
public String getName() {
return NAME;
}
public void response(String message) {
System.out.println("==================="+NAME+"收到气象信息===================");
System.out.println("气象信息:"+message+"n");
}
}
HNDObservable.java
public class HNDObservable implements WeatherObservable {
private final String NAME="海南岛气象站";
@Override
public String getName() {
return NAME;
}
public void response(String message) {
System.out.println("==================="+NAME+"收到气象信息===================");
System.out.println("气象信息:"+message+"n");
}
}
TWObservable.java
public class TWObservable implements WeatherObservable {
private final String NAME="台湾气象站";
@Override
public String getName() {
return NAME;
}
public void response(String message) {
System.out.println("==================="+NAME+"收到气象信息===================");
System.out.println("气象信息:"+message+"n");
}
}
ISubject.java
public interface ISubject {
void attach(WeatherObservable observer);
void remove(WeatherObservable observer);
void notifyAllObservers();
WeatherSubject.java
public class WeatherSubject implements ISubject {
private List observers
= new ArrayList();
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
notifyAllObservers();
}
public void attach(WeatherObservable observer) {
observers.add(observer);
System.out.println(">>>>>>>>>>>>>添加"+observer.getName());
}
@Override
public void remove(WeatherObservable observer) {
if(observers.remove(observer)){
System.out.println(">>>>>>>>>>>>>移除"+observer.getName());
}
}
public void notifyAllObservers() {
System.out.println("----------------------------开始订阅----------------------------");
for (WeatherObservable observer : observers) {
observer.response(message);
}
System.out.println("----------------------------订阅结束----------------------------");
}
}
Test.java
public class Test {
public static void main(String[] args) {
WeatherSubject subject=new WeatherSubject();
FJObservable fjObservable = new FJObservable();
GDObservable gdObservable = new GDObservable();
TWObservable twObservable = new TWObservable();
HNDObservable hndObservable = new HNDObservable();
subject.attach(fjObservable);
subject.attach(gdObservable);
subject.attach(twObservable);
subject.attach(hndObservable);
subject.setMessage("两日后即将迎来10级台风,请做好应急准备");
subject.remove(gdObservable);
subject.remove(fjObservable);
subject.setMessage("两日后即将迎来10级台风,请做好应急准备");
}
}
执行结果
如上所示,我们可以动态添加或者删除观察者来广播消息
优化思路: 可以将观察者改成一个map接收,保证不会添加重复气象站
注:上面源码中含有线程监听代码,有兴趣可以自己看下



