观察者模式:
概念:定义对象间的一种一对多的依赖关系。当一个对象的状态发生变化时,所有依赖它的对象都得到了通知并自动更新。
一个软件系统里面包含了各种对象,就像一片欣欣向荣的森林充满了各种生物一样。在一篇森林中,各种生物彼此依赖和约束,形成一个个生物链。一种生物的状态变化会造成其它生物的相应行动,每一个生物都处于别的生物的互动中。
角色概念:
- Subject(被观察者): 提供一个具体被观察者的接口,定义了添加,移除,通知等操作。
- ConcreteSubject(具体被观察者):实现或者继承Subject,将有关状态存入具体观察者对象,在内部状态变化时,通知其内所有ConcreteObserver(具体观察者)。
- Observer(抽象观察者):提供一个具体观察者的接口,定义了实现通知的方法。
- ConcreteObserver(具体观察者):实现Observer,实现或者继承通知方法,根据不同的需求,添加自己的逻辑代码。
实现这样一个逻辑demo:当订阅一个微信公众号时,如果这个微信公众号,有新的推送消息,就会收到这个推送消息。这里,微信公众号就是一个被观察者(Subject),其中的一个公众号就是具体被观察者(ConcreteSubject)。全部的订阅者是观察者(Observer),其中的一个就是具体观察者(ConcreteObserver)。
观察者模式分为推模型和拉模型,这个是推模型:
Subject(公众号代码):
/**
* Created by user on 2017/4/7.
* 微信公众号
*/
public abstract class Subject{
//用来保存观察者对象
private List<Observer> observers=new ArrayList<>();
//实现被观察者的三个方法 attach 、detach、notifyObserver
/**
* 添加观察者(即一个订阅者订阅这个公众号)
*/
public void attach(Observer observer){
observers.add(observer);
}
/**
*去除观察者(即一个订阅者取消订阅这个公众号)
*/
public void detach(Observer observer){
observers.remove(observer);
}
/**msg
* 通知观察者(订阅号有新消息了,去通知每一个订阅者)
*/
protected void notifyObserver(String msg){
for(Observer observer:observers){
observer.updateMsg(msg);
}
}
}
ConcreteSubject(一个公众号):
/**
* Created by user on 2017/4/7.
* 一个具体的公众号
*/
public class ConcreteSubject extends Subject {
//更新的消息
private String msg;
public String getMsg(){
return msg;
}
/**
* 公众号有新的信息要推送了
*/
protected void update(String newMsg){
msg=newMsg;
Log.i("Tag8","公众号要推送消息是:"+msg);
//把新消息推送给所有订阅者 这块子类如果进行复写,那么调用子类的,如果没有实现,就调用父类的
this.notifyObserver(msg);
}
}
Observer(所有订阅者):
/**
* Created by user on 2017/4/7.
* 所有订阅者
*/
public interface Observer {
//更新公众号推送过来的信息
public void updateMsg(String msg);
}
ConcreteObserver(一个订阅者):
/**
* Created by user on 2017/4/7.
* 一个具体的公众号
*/
public class ConcreteSubject extends Subject {
//更新的消息
private String msg;
public String getMsg(){
return msg;
}
/**
* 公众号有新的信息要推送了
*/
protected void update(String newMsg){
msg=newMsg;
Log.i("Tag8","公众号要推送消息是:"+msg);
//把新消息推送给所有订阅者 这块子类如果进行复写,那么调用子类的,如果没有实现,就调用父类的
this.notifyObserver(msg);
}
}
一个用户订阅一个公众号,并推送一条消息代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获得这个公众号的对象
ConcreteSubject concreteSubject=new ConcreteSubject();
//获得这个用户对象
ConcreteObserver concreteObserver=new ConcreteObserver();
//用户去订阅这个公众号
concreteSubject.attach(concreteObserver);
concreteSubject.update("you are my sunshine");
}
这里直接用android代码里写了,就不写main函数了,上面可以去写多个类去实现Observer,每一个类都是一个用户,detach()就不去写了,取消订阅对应这步操作。
拉模型:
这个也用微信公众号举例,当我们订阅一个微信公众号是,很多时候都会看到底部下面的几个条目,当选择其中一个条目时,就会发过来对应的这条消息条目的信息。和推模型相比这个是选择性获取的,传递的不再是一个String类型的msg消息,而是一个Observer对象,接收这个对象,获取对象里面你所需要的消息。
与推模型相比,拉模型改动部分:
- ConcreteSubject(用户接收的是推送过来的对象)
/**msg
* 通知观察者(订阅号有新消息了,去通知每一个订阅者)
*/
protected void notifyObserver(){
for(Observer observer:observers){
observer.updateMsg(this);
}
}
- Observer(所有订阅者)
public interface Observer {
//更新公众号推送过来的信息
public void updateMsg(Subject subject);
}
- ConcreteObserver(一个订阅者)
public class ConcreteObserver implements Observer {
@Override
public void updateMsg(Subject subject) {
//得到的ConcreteSubject的对象
ConcreteSubject concreteSubject=(ConcreteSubject)subject;
//通过这个对象,我们获取指定的想要拉取的消息
Log.i("Tag8","用户接收到的消息是:"+concreteSubject.getMsg());
}
}
拉模型完成代码:
/**
* Created by user on 2017/4/7.
* 微信公众号
*/
public abstract class Subject{
//用来保存观察者对象
private List<Observer> observers=new ArrayList<>();
//实现被观察者的三个方法 attach 、detach、notifyObserver
/**
* 添加观察者(即一个订阅者订阅这个公众号)
*/
public void attach(Observer observer){
observers.add(observer);
}
/**
*去除观察者(即一个订阅者取消订阅这个公众号)
*/
public void detach(Observer observer){
observers.remove(observer);
}
/**msg
* 通知观察者(订阅号有新消息了,去通知每一个订阅者)
*/
protected void notifyObserver(){
for(Observer observer:observers){
observer.updateMsg(this);
}
}
}
/**
* Created by user on 2017/4/7.
* 一个具体的公众号
*/
public class ConcreteSubject extends Subject {
//更新的消息
private String msg;
public String getMsg(){
return msg;
}
/**
* 公众号有新的信息要推送了
*/
protected void update(String newMsg){
msg=newMsg;
Log.i("Tag8","公众号要推送消息是:"+msg);
//把新消息推送给所有订阅者 这块子类如果进行复写,那么调用子类的,如果没有实现,就调用父类的
this.notifyObserver();
}
}
public interface Observer {
//更新公众号推送过来的信息
public void updateMsg(Subject subject);
}
public class ConcreteObserver implements Observer {
@Override
public void updateMsg(Subject subject) {
//得到的ConcreteSubject的对象
ConcreteSubject concreteSubject=(ConcreteSubject)subject;
//通过这个对象,我们获取指定的想要拉取的消息
Log.i("Tag8","用户接收到的消息是:"+concreteSubject.getMsg());
}
}
结论:就写到这里了,有问题就说,再去修改,另外Java提供了观察者观察者Observer接口,和被观察者Observable抽象类,用的时候,直接实现和继承就可以了^…^~~