观察者模式:
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
涉及设计原则:
1.为了交互对象之间的松耦合设计而努力
2.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
3.针对接口编程,不针对实现编程
4.多用组合,少用继承
问题简单描述:
多个读者订阅同一个报社的报纸,需要实现报社没更新一版报纸,订阅的读者都会收到新的报纸。
解决思路:
报纸实现主题接口(包含添加观察者、移除观察者、通知观察者基本方法),读者实现观察者接口(包含更新基本方法)。报纸中包含观察者队列,主题和观察者形成一对多关联。报纸每发布新消息,都遍历观察者队列通知每一个观察者。读者初始化或用set方法订阅主题。
UML图:
实现代码:
主题接口
package observer;
/**
* 主题接口
* author terry
*
*/
public interface Subject {
//让观察者关注主题
public void registObserver(Observer observer);
//让观察者取消关注主题
public void removeObserver(Observer observer);
//主题修改信息,推送信息
public void notifyObservers();
}
观察者接口
package observer;
/**
* 观察者实现接口
* @author terry
*
*/
public interface Observer {
//观察者接收主题消息
public void update(NewsInfo newsInfo);
}
NewsInfo(模拟推送信息)
package observer;
/***
* 主题推送内容
* @author terry
*
*/
public class NewsInfo {
private String message;
private String pic;
public NewsInfo(){
}
public NewsInfo(String message, String pic) {
super();
this.message = message;
this.pic = pic;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
@Override
public String toString() {
return "NewsInfo [message=" + message + ", pic=" + pic + "]";
}
}
人民日报(主题实现类)
package observer;
import java.util.ArrayList;
import java.util.List;
/**
* 人民日报
* @author terry
*
*/
public class RenMinNewspaper implements Subject {
//订阅主题的观察者
private List<Observer> observers;
//消息
private NewsInfo newsInfo;
public RenMinNewspaper(){
observers=new ArrayList<>();
}
@Override
public void registObserver(Observer observer) {
//观察者添加到list
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
//观察者从list中移除
int idx=observers.indexOf(observer);
if(idx>=0){
observers.remove(idx);
}
}
@Override
public void notifyObservers() {
//通知所有观察者
for(Observer observer:observers){
//调用update方法(推消息是调用,如果观察者主动拉主题消息不需要调用)
observer.update(newsInfo);
}
}
//报社发报
public void publishNewspaper(){
notifyObservers();
}
public List<Observer> getObservers() {
return observers;
}
public void setObservers(List<Observer> observers) {
this.observers = observers;
}
public NewsInfo getNewsInfo() {
return newsInfo;
}
public void setNewsInfo(NewsInfo newsInfo) {
this.newsInfo = newsInfo;
//每次修改信息时发报
publishNewspaper();
}
}
钱江日报(主题实现类)
package observer;
import java.util.ArrayList;
import java.util.List;
public class QianJiangNewspaper implements Subject{
private List<Observer> observers;
private NewsInfo newsInfo;
public QianJiangNewspaper(){
observers=new ArrayList<>();
}
@Override
public void registObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
int i=observers.indexOf(observer);
if(i>=0){
observers.remove(i);
}
}
@Override
public void notifyObservers() {
for(Observer observer:observers){
observer.update(newsInfo);
}
}
public void publishNewspaper(){
notifyObservers();
}
public List<Observer> getObservers() {
return observers;
}
public void setObservers(List<Observer> observers) {
this.observers = observers;
}
public NewsInfo getNewsInfo() {
return newsInfo;
}
public void setNewsInfo(NewsInfo newsInfo) {
this.newsInfo = newsInfo;
publishNewspaper();
}
}
Reader1(观察者实现类)
package observer;
public class Reader1 implements Observer{
//消息
private NewsInfo newsInfo;
//主题
private Subject subject;
public Reader1(Subject subject){
//设置主题
this.subject=subject;
//注册到主题
subject.registObserver(this);
}
@Override
public void update(NewsInfo newsInfo) {
this.newsInfo=newsInfo;
doReading();
}
public void doReading(){
System.out.println("Reader1:"+newsInfo.toString());
}
public Subject getSubject() {
return subject;
}
//添加主题set方法可以动态修改主题
public void setSubject(Subject subject) {
this.subject = subject;
subject.registObserver(this);
}
}
Reader2(观察者实现类)
package observer;
public class Reader2 implements Observer{
private NewsInfo newsInfo;
private Subject subject;
public Reader2(Subject subject){
this.subject=subject;
subject.registObserver(this);
}
@Override
public void update(NewsInfo newsInfo) {
this.newsInfo=newsInfo;
doReading();
}
public void doReading(){
System.out.println("Reader2:"+newsInfo.toString());
}
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
subject.registObserver(this);
}
}
测试类
package observer;
public class Test {
public static void main(String[] args) {
RenMinNewspaper renMinNewspaper=new RenMinNewspaper();
QianJiangNewspaper qianJiangNewspaper=new QianJiangNewspaper();
//两个读者关注人民日报
Reader1 reader1=new Reader1(renMinNewspaper);
Reader2 reader2=new Reader2(renMinNewspaper);
//人民日报发布新新闻
renMinNewspaper.setNewsInfo(new NewsInfo("消息1","图片1"));
renMinNewspaper.setNewsInfo(new NewsInfo("消息2","图片2"));
//读者2取消关注人民日报
renMinNewspaper.removeObserver(reader2);
renMinNewspaper.setNewsInfo(new NewsInfo("消息3","图片3"));
//读者2关注钱江日报
reader2.setSubject(qianJiangNewspaper);
//钱江日报发布新闻
qianJiangNewspaper.setNewsInfo(new NewsInfo("消息4","图片4"));
//人民日报发布新闻
renMinNewspaper.setNewsInfo(new NewsInfo("消息5","图片5"));
}
}
输出结果
观察者模式中主题不必知道自己的观察者的细节信息,主题只依赖观察者的接口。观察者的增加、删除、修改都不会对主题造成影响。主题只需要把消息推送给所有实现了观察者接口的观察者。这样主题和观察者之间就是松耦合,可以自由的改变、复用主题跟观察者。还是一个因为接口变得很神奇的模式。java内置观察者模式,但是主题是作为超类需要主题实现类去继承,继承自然就会有很多问题。而且自己写一个主题接口也并不难,这里就没有再用java内置的观察者模式。
欢迎批评指正^ ^