简介:观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
观察者模式使用的六个重要的方面
1:确定目标与观察者的之间的关系(是多对一还是一对多等等)
2:它们之间的关系是单方向依赖(观察者和目标是单向依赖的主动权在目标手中)
3:命名建议
(1)目标接口的定义,建议在名称后面跟Subject
(2)观察者接口定义,建议在名称后面跟Observer
(3)观察者接口的更新方法,建议在名称为update
4:触发通知的时机(要在完成数据状态维护之后触发通知,不然会造成通知数据的错误)
5:观察者模式的调用顺序示意图
![这里写图片描述](https://img-blog.csdn.net/20160604095036940)、
6:通知顺序(多个观察的顺序是平行的,互相不应该存在有依赖关系)
建议以下情况下使用观察者模式
1.当一个抽象模型有俩个方面,其中一个方面的操作依赖与另一个方面的状态变化
2.如果在更改一个对象的时候需要连带修改其他的对象,而且不知道究竟应该有多少对象需要被连带修改
3.当一个对象必须通知其他的对象,但是又希望这个对象和其他被他通知的对象时松散耦合的
这就是观察者模式的一个简单的结构图
Attach:是注册观察者
Detach:是删除观察者
Notify:是通知所有的观察者
Update:获取目标类的状态同步到观察者的状态中
源码实现拉模型的例子:推模型就是把注释有拉模型的注释掉,把注释有推模型的释放出来
Observer.java
/**
* @ClassName: Observer
* @Description: 这是一个观察着的接口 定义一个更新的接口给那些在目标发生改变的时候被通知的对象
* @author: Administrator
* @date: 2016年5月31日 下午3:55:32
*/
public interface Observer {
//观察者自动更新的接口 subject是传入目标对象的状态 方便获取相应的目标对象的状态
//public void update(WeatherSubject subject);//拉模型
public void update(String content);//推模型
}
ConcreteWeatherSubject.java
/**
* @ClassName: ConcreteSubject
* @Description: 具体的一个目标对象 负责把有关状态存入相应的观察着对象中
* @author: Administrator
* @date: 2016年5月31日 下午3:53:53
*/
public class ConcreteWeatherSubject extends WeatherSubject{
//目标对象的状态信息
private String weatherContent;
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
//这表示状态发生改变的时候就会通知每一个观察者
//this.notifyObservers();//拉模型
this.notifyObservers(weatherContent);//推模型
}
}
ConcreteObserver.java
/**
* @ClassName: ConcreteObserver
* @Description: 这是一个具体观察者对象 实现更新方法 是自身的状态和目标状态保持一致
* @author: Administrator
* @date: 2016年5月31日 下午3:58:20
*/
public class ConcreteObserver implements Observer {
//观察者的状态名字
private String observerName;
//观察者所要知道的信息 这个消息从目标处获取
private String weatherContent;
//提醒的内容 不同的观察者要提醒不同的内容
private String remindThing;
//获取目标类的状态的同步道观察者的状态中
@Override
//public void update(WeatherSubject subject) {//拉模型
public void update(String content){//推模型
//weatherContent=((ConcreteWeatherSubject)subject).getWeatherContent();//拉模型
weatherContent=content;//推模型
System.out.println(observerName+"收到了"+weatherContent+","+remindThing);
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
}
public String getRemindThing() {
return remindThing;
}
public void setRemindThing(String remindThing) {
this.remindThing = remindThing;
}
}
WeatherSubject.java
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: Subject
* @Description: 目标对象 它知道观察它的观察着 并提供注册(添加)和删除观察者的接口
* @author: Administrator
* @date: 2016年5月31日 下午3:50:47
*/
public class WeatherSubject {
//用来保存注册的观察者的对象
private List<Observer> observers = new ArrayList<Observer>();
//attach detach notifyObervers
//添加集合观察者
public void attach(Observer observer){
observers.add(observer);
}
//删除集合中的观察者
public void detach(Observer observer){
observers.remove(observer);
}
//通知所有注册的观察者对象
// protected void notifyObservers(){//拉模型
protected void notifyObservers(String content){//推模型
for(Observer observer:observers){
//observer.update(this);//拉模型
observer.update(content);//推模型
}
}
}
测试运行的Client.java
public class Client {
public static void main(String[] args) {
//1创建一个目标
ConcreteWeatherSubject weather = new ConcreteWeatherSubject();
//2创建观察者
ConcreteObserver observerGril = new ConcreteObserver();
observerGril.setObserverName("姚鸿的女朋友");
observerGril.setRemindThing("第一次约会的地点,大连民族学院南门,不见不散哦");
ConcreteObserver observerBoy = new ConcreteObserver();
observerBoy.setObserverName("夏文齐");
observerBoy.setRemindThing("走,去吃饭");
//注册观察者
weather.attach(observerGril);
weather.attach(observerBoy);
//4目标发布的天气
weather.setWeatherContent("没下雨");
}
}
直接用java的函数实现
Client.java
/**
* @ClassName: Client
* @Description: 测试类
* @author: Administrator
* @date: 2016年5月31日 下午8:34:19
*/
public class Client {
public static void main(String[] args) {
//创建天气作为一个目标 也可以说是被观察
ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
//创建一个观察者
ConcreteObserver gril = new ConcreteObserver();
gril.setObserverName("小花");
//创建第二个观察者
ConcreteObserver boy = new ConcreteObserver();
boy.setObserverName("兄弟");
//注册观察者
subject.addObserver(gril);
subject.addObserver(boy);
//目标更新的情况
subject.setContent("今天天气不错哦");
}
}
ConcreteObserver.java
import java.util.Observable;
import java.util.Observer;
/**
* @ClassName: ComcreteObserver
* @Description: 具体的观察者对象
* @author: Administrator
* @date: 2016年5月31日 下午8:29:08
*/
public class ConcreteObserver implements Observer {
//观察者的名称对象
private String observerName;
@Override
public void update(Observable o, Object arg) {
//第一种是推的方式
System.out.println(observerName+"收到了消息,目标推送过来的是"+arg);
//第二种是拉的方式
System.out.println(observerName+"收到消息,主动到目标对象中去拉,拉的内容是"+
((ConcreteWeatherSubject)o).getContent());
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
}
ConcreteWeatherSubject.java
import java.util.Observable;
//天气目标的具体实现类
public class ConcreteWeatherSubject extends Observable{
//天气情况的内容
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
//天气情况有了 通知所有的观察者
//注意通知之前 在用java中的Observer模式的时候 下面的这句话不可少
this.setChanged();
//然后主动通知 notifyObservers()不带参数的是拉模型 带参数的推模型
this.notifyObservers(content);
//this.notifyObservers();//拉模型
}
}