本文是自己在慕课网学习java设计模式之观察者模式的个人笔记,便于以后查看
目标与观察者之间的关系
一对多的关系
一对一的关系(如果观察者只有一个)
单向依赖
在观察者模式中,观察者和目标是单向依赖,只有观察者依赖目标,而不是目标依赖观察者。主动权掌握在目标手中,只有目标知道什么时候需要通知观察者。
触发通知的时机
一般情况下,是在完成了状态维护后触发。因为通知会传递数据,不能先通知,后改数据,这会导致观察者和目标对象状态不一致。
以下是自己跟做的demo,天气demo(课程中就是这个)
package Observer_design.Weather;
import java.util.ArrayList;
public class WeatherSubject {
ArrayList<Observer> observers = new ArrayList<Observer>();
// 增加观察者
public void attach(Observer observer) {
observers.add(observer);
}
// 移除观察者
public void detach(Observer observer) {
observers.remove(observer);
}
// 发布消息给所有的观察者
public void notifyObservers(){
for (Observer observer : observers) {
observer.update(this);
}
}
}
package Observer_design.Weather;
public class ConcreteWeatherSubject extends WeatherSubject {
private String weatherContent;
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
//发布最新的消息给观察者
this.notifyObservers();
}
}
package Observer_design.Weather;
public interface Observer {
public void update(WeatherSubject weatherSubject);
}
package Observer_design.Weather;
public class ConcreteObserver implements Observer {
private String onserverName;
private String weatherContent;
private String remindContent;
public String getOnserverName() {
return onserverName;
}
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
}
public void setOnserverName(String onserverName) {
this.onserverName = onserverName;
}
public String getRemindContent() {
return remindContent;
}
public void setRemindContent(String remindContent) {
this.remindContent = remindContent;
}
@Override
public void update(WeatherSubject subject) {
weatherContent= ((ConcreteWeatherSubject)subject).getWeatherContent();
System.out.println(onserverName+"收到信息"+weatherContent+","+remindContent);
}
}
测试:
package Observer_design.Weather;
public class test1 {
public static void main(String[] args) {
ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
ConcreteObserver girl = new ConcreteObserver();
girl.setOnserverName("女友");
girl.setRemindContent("约会");
subject.attach(girl);
ConcreteObserver mum = new ConcreteObserver();
mum.setOnserverName("老妈");
mum.setRemindContent("购物");
subject.attach(mum);
subject.setWeatherContent("天气很好");
}
}
实验结果
女友收到信息天气很好,约会
老妈收到信息天气很好,购物
以上的很多工作,例如观察者的接口和目标类的定义,在jdk中有现成接口供观察者模式使用。
具体的目标里面就不需要在维护观察者的注册信息了
触发通知的方式有一点变化,要先调用setChanged方法,这是为了实现更精确的触发控制
具体观察者的实现里面,update方法能同时支持推模型和拉模型
package Observer_design.weather2;
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;
this.setChanged();
this.notifyObservers(content);
}
}
package Observer_design.weather2;
import java.util.Observable;
import java.util.Observer;
public class ConcreteObserver implements Observer {
private String observerName;
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
@Override
public void update(Observable observer, Object arg) {
// 推模型
System.out.println(observerName + " 收到了消息,目标推送过来的是 "+arg);
}
}
测试:
package Observer_design.weather2;
public class test {
public static void main(String[] args) {
//创建目标
ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
//创建观察者
ConcreteObserver girl = new ConcreteObserver();
girl.setObserverName("girl");
subject.addObserver(girl);
//注册观察者
ConcreteObserver mum = new ConcreteObserver();
mum.setObserverName("mum");
subject.addObserver(mum);
//推送文章
subject.setContent("天气很好很好");
}
}
结果:
mum 收到了消息,目标推送过来的是 天气很好很好
girl 收到了消息,目标推送过来的是 天气很好很好
该为拉模型
@Override
public void update(Observable observer, Object arg) {
// 推模型
//System.out.println(observerName + " 收到了消息,目标推送过来的是 "+arg);
//拉模型
System.out.println(observerName + " 收到了消息,目标推送过来的是 "+((ConcreteWeatherSubject)observer).getContent());
}
测试结果不变。
3-4 优点缺点(摘抄慕课网)
简述观察者优缺点
优点
观察者模式实现了观察者和目标之间的抽象耦合
观察者模式实现了动态联动(所谓联动是指做一个操作会引起其它相关的操作)
观察者模式支持广播通信
缺点
可能会引起无谓的操作
3-5 何时使用(摘抄慕课网)
观察者模式的本质
触发联动
建议在以下情况中选用观察者模式
当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化
如果在更改一个对象的时候,需要同时连带改变其他的对象,
而且不知道究竟应该有多少对象需要被连带改变
当一个对象必须通知其他的对象,但是又希望这个对象和被它通知的对象是松散耦合的
但是在实际上,有时需要对发布的消息进行判断,对观察者接受消息进行区分。
我对上面这个例子进行修改,下雨时对女孩进行通知,天晴是对男孩进行通知
package Observer_design.weather3;
import java.util.ArrayList;
public abstract class WeatherSubject {
ArrayList<Observer> observers = new ArrayList<Observer>();
// 增加观察者
public void attach(Observer observer) {
observers.add(observer);
}
// 移除观察者
public void detach(Observer observer) {
observers.remove(observer);
}
// 发布消息给所有的观察者
public abstract void notifyObservers();
}
package Observer_design.weather3;
import java.util.Objects;
public class ConcreteWeatherSubject extends WeatherSubject {
private String weatherContent;
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
//发布最新的消息给观察者
this.notifyObservers();
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
if(Objects.equals("下雨", this.weatherContent)){
if(((ConcerteObserver)observer).getObserverName().equals("girl")){
observer.update(this);
}
}else if(Objects.equals("晴天", this.weatherContent)){
if(((ConcerteObserver)observer).getObserverName().equals("mum")){
observer.update(this);
}
}
}
}
}
package Observer_design.weather3;
public interface Observer {
public void update(WeatherSubject weatherSubject);
}
package Observer_design.weather3;
public class ConcerteObserver implements Observer {
private String observerName;
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
@Override
public void update(WeatherSubject weatherSubject) {
String weatherContent = ((ConcreteWeatherSubject)weatherSubject).getWeatherContent();
System.out.println(observerName+"收到了"+weatherContent);
}
}
测试:
package Observer_design.weather3;
public class test3 {
public static void main(String[] args) {
ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
ConcerteObserver girl = new ConcerteObserver();
girl.setObserverName("girl");
subject.attach(girl);
ConcerteObserver mum = new ConcerteObserver();
mum.setObserverName("mum");
subject.attach(mum);
subject.setWeatherContent("下雨");
}
}
测试结果:
girl收到了下雨
修改为天晴
结果为;
mum收到了晴天
所以这个具有区分判断是否发布个某个观察者的观察者模式就算测试成功了。
在以上的理论知识与demo绝大部分是来自慕课网(我挺喜欢的一个平台)