简介
观察者模式属于行为模式,是一种非常常见的一种设计模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并且自动更新。通常使用与事件处理系统。
结构:
主要为观察对象(主题)与观察目标(观察者角色),为了符合DIP原则,不让他直接依赖于具体实现,我们需要将其抽象出来
1.抽象主题角色(Subject):把所有对观察者对象的应用保存到一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加删除观察者角色。一般使用抽象类或者接口来实现。
2.抽象观察者角色(ConcreteSubject):为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
3.具体主题角色(Observer):在具体主题内部状态改变时,给所有登记过的观察者发出通知,具体主题角色通常用一个子类实现。通常用一个子类实现。
4.具体观察者角色(ConcrereObserver):实现抽象观察者角色所要求的更新接口,方便本身的状态与主题的状态协调。通常使用子类实现,吐过需要,具体观察者角色可以保存一个指向具体主题角色的应用。
观察者模式解决什么问题?
观察者模式主要解决的是轮询通知:当观察主题改变时会触发观察者发生改变。避免了不必要的资源浪费。
比如这样的场景:有一个气象站,你想要知道温度变了么,你需要打电话去询 温度变了么?气象站说变了,你才知道变了。
但是使用观察者模式,你只需要流一个电话,当温度有变化时候他会群发告诉你温度变了。
在实际上我们使用都是抽象类或者接口来进行沟通,这样才符合DIP原则。
代码案例
(观察者模式分为推模式和拉模式,这里先从一个简单的案例开始理解,另外两个模式在观察者模式(2)中讲解)
这里依然使用开始举例的气象站
//抽象观察主题
public interface WeatherSubject {
//注册
void registerObserver(Observer ob);
//删除
void removeObserver(Observer ob);
//通知
void notifyObserver();
}
//抽象观察者角色
public interface Observer {
//更新
void update();
}
//具体观察者角色张三
public class ZhangSanOb implements Observer {
//引入观察主题对象
WeatherStation ws;
public ZhangSanOb(WeatherStation ws) {
this.ws = ws;
}
@Override
public void update() {
System.out.println("张三收到通知 更新温度:"+ws.getTemperature()+" 湿度:"+ws.getDamness());
}
}
//具体观察者角色李四
public class LiSiOb implements Observer{
WeatherStation ws;
public LiSiOb(WeatherStation ws) {
this.ws=ws;
// TODO Auto-generated constructor stub
}
@Override
public void update() {
System.out.println("李四收到通知 更新温度:"+ws.getTemperature()+" 湿度:"+ws.getDamness());
}
}
//具体观察主题
public class WeatherStation implements WeatherSubject {
//观察者集合
List<Observer> list=new ArrayList<Observer>();
//温度
private int temperature=0;
//湿度
private int damness=0;
@Override
public void registerObserver(Observer ob) {
list.add(ob);
}
@Override
public void removeObserver(Observer ob) {
list.remove(ob);
}
@Override
public void notifyObserver() {
//遍历观察者集合 给每个观察者进行更新
for (Observer observer : list) {
observer.update();
}
}
//set方法调用时 说明主题发生改变,所以我们需要调用通知方法
public void setTemperature(int temperature) {
this.temperature = temperature;
notifyObserver();
}
public void setDamness(int damness) {
this.damness = damness;
notifyObserver();
}
//省略get方法
}
测试结果
public class Client {
public static void main(String[] args) {
//创建观察主题对象
WeatherStation ws=new WeatherStation();
//创建观察者对象 张三 李四
ZhangSanOb zsOb=new ZhangSanOb(ws);
LiSiOb liSiOb=new LiSiOb(ws);
//为观察目标注册观察者
ws.registerObserver(zsOb);
ws.registerObserver(liSiOb);
//设置温度
ws.setDamness(51);
//设置湿度
ws.setTemperature(-5);
}
}
结果:
张三收到通知 更新温度:0 湿度:51
李四收到通知 更新温度:0 湿度:51
张三收到通知 更新温度:-5 湿度:51
李四收到通知 更新温度:-5 湿度:51
看过设计模式中的设计原则的同学应该能看的出来 这里我们每个观察者对象都引用了一个观察目标的一个对象,这样是不合理的设计 所以我把真正的推模式案例和拉模式 写在设计模式专栏中:观察者模式(2)。