(十五)观察者模式(Observer)
最后更新于:2022-04-01 15:48:37
观察者模式(Observer)就是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。
对于观察者模式的原理图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_57845609e7d48.gif)
通过一个一个抽象的主题Subject保存了多个信息处理列表,可以添加多个观察者,实现即时的通知观察者最新动态然后分别派生子类对象对具体的消息和状态做出处理,下面我们联系到具体的问题:正好我还在读,就拿学校通知公告来举例子吧,学校发布一个公告,要通知学生,老师,保洁阿姨,和食堂等相应的通知,这样才能正常的进行工作,比如这次清明放假,要通知所有机关和单位做好准备,这样才能保证正常有序的进行,下面是简单的原理图和例子程序:
换了一个UML这次用的一个jude很好的简单实用,而且这个是免安装的
提供了一下下载地址
[http://download.csdn.net/detail/wclxyn/4226796](http://download.csdn.net/detail/wclxyn/4226796)(不需要财富值)
示例原理图(新手原理图不对之处请多多指教)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560a05348.gif)
首先定义接口观察者,定义接受消息的方法,具体内容如下:
~~~
package com.designpattern.observer;
public interface Observer {
public void receive(String message);
}
~~~
然后分别写教师,学生,食堂,保洁观察者的实现类:
~~~
package com.designpattern.observer;
public class Teachers implements Observer {
@Override
public void receive(String message) {
System.out.println("教师收到" + message);
}
}
~~~
~~~
package com.designpattern.observer;
public class Students implements Observer {
@Override
public void receive(String message) {
System.out.println("学生收到" + message);
}
}
~~~
~~~
package com.designpattern.observer;
public class Mess implements Observer {
@Override
public void receive(String message) {
System.out.println("食堂收到" + message);
}
}
~~~
~~~
package com.designpattern.observer;
public class Cleaner implements Observer {
@Override
public void receive(String message) {
System.out.println("保洁收到" + message);
}
}
~~~
然后定义被观察者接口,具体这里是学校,定义了通知公告的方法announcement方法和提醒方法notifyReceive方法同时定义add和romove观察者的方法,这里用synchronized控制添加和移除,为了操作的便捷,定义返回值为School,这样能连续操作,如下:
~~~
office.addObserver(new Mess()).addObserver(new Students()).addObserver(
new Teachers()).addObserver(new Cleaner());
~~~
具体的School如下:
~~~
package com.designpattern.observer;
import java.util.ArrayList;
import java.util.List;
public abstract class School {
private List<Observer> observers = new ArrayList<Observer>();
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void announcement() {
notifyRecevie();
}
public synchronized School addObserver(Observer observer) {
observers.add(observer);
return this;
}
public synchronized School removeObserver(Observer observer) {
observers.remove(observer);
return this;
}
public void notifyRecevie() {
for (int i = 0; i < observers.size(); i++) {
Observer observer = (Observer) observers.get(i);
observer.receive(getMessage());
}
}
}
~~~
然后具体的实例类Office进行具体的通知:
~~~
package com.designpattern.observer;
public class Office extends School {
@Override
public void announcement() {
System.out.println("政教处通知明天放假");
this.setMessage("明天放假");
super.announcement();
System.out.println("---------------------");
}
}
~~~
之后客户端调用:
~~~
package com.designpattern.observer;
public class Client {
public static void main(String[] args) {
Office office = new Office();
office.addObserver(new Mess()).addObserver(new Students()).addObserver(
new Teachers()).addObserver(new Cleaner());
office.announcement();
}
}
~~~
然后打印结果如下,如果动态的添加和移除观察者都能实现通知:
~~~
政教处通知明天放假
食堂收到明天放假
学生收到明天放假
教师收到明天放假
保洁收到明天放假
---------------------
~~~
在java的API里面也封装好了这样一个观察者的接口
具体的实例时观察者继承Observer类,被观察者实现Observable接口然后调用其中的具体方法,操作很简单具体参见API就可以了,简单些了一个小Demo:
~~~
package wlzx.mh.observer;
import java.util.Observable;
public class House extends Observable {
private float price;
private String name;
public String getName() {
return name;
}
public House(float price) {
this.price = price;
}
public String toString(){
return "House.java" ;
}
public float getPrice() {
return price;
}
public void setName(String name) {
this.name = name;
super.setChanged();
super.notifyObservers(name);
}
public void setPrice(float price) {
super.setChanged();// 通知内容已经可以被修改了
this.price = price;
// 一旦修改,则表示价格改变,那么价格改变之后,实际上应该立刻通知所有的观察者
super.notifyObservers(price);// 通知所有的观察者已经改变
}
}
~~~
~~~
package wlzx.mh.observer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Observable;
import java.util.Observer;
public class Person implements Observer {
// arg表示改变之后的内容
// o表示观察的对象
public String getDateTime() {
return (new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS")
.format(new Date())).toString();
}
public void update(Observable o, Object arg) {
System.out.println(getDateTime() + "----" + o + "----" + arg);
}
}
~~~
~~~
package wlzx.mh.observer;
public class TestObserver {
public static void main(String[] args) {
House h = new House(3000.0f);
Person per1 = new Person();
Person per2 = new Person();
Person per3 = new Person();
h.addObserver(per1);// 增加一个观察者
h.addObserver(per2);// 增加一个观察者
h.addObserver(per3);// 增加一个观察者
h.setPrice(6000.0f);// 要通知观察者内容已经被改变了
h.setName("wclxyn");
}
}
~~~
~~~
2012-04-14 11:44:30.578----House.java----6000.0
2012-04-14 11:44:30.578----House.java----6000.0
2012-04-14 11:44:30.578----House.java----6000.0
2012-04-14 11:44:30.578----House.java----wclxyn
2012-04-14 11:44:30.578----House.java----wclxyn
2012-04-14 11:44:30.578----House.java----wclxyn
~~~
这样具体的内容改变都会被监控了。
观察者模式在被观察者和观察者之间建立一个抽象的耦合,每一个具体的观察者都符合一个抽象观察者的接口,被观察者并不知道任何一个具体的观察者,他只知道他们有一个共同的接口,从而使得被观察者和观察者耦合度降低,而且观察者模式支持广播通信。被观察者会向所有注册过的观察者发出通知,但是如果一个被观察者有N个观察者那么在通知过程种会耗费大量的时间。