一、观察者模式
观察者的通俗理解可以参考订阅发布的方式,每一个订阅内容,一旦被观察对象内容改变就会向观察者发送消息,告诉观察者修改了内容或者是观察者获取最新内容
- Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,Subject已经通过方法已经定义好了业务逻辑。抽象主题所要做的就是实现attach()添加观察者,detach()删除观察者,notify()向观察者发送消息(调用update)
- ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。主要是将notify()的封装
- Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。主要定义update方法,可以定义为接受具体信息(通过被观察者推送消息的模式),或者接受被观察者的引用(通过观察者拉取消息的模式)
- ConcrereObserver:具体观察者,是实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
二、订阅/发布模式(push模式)
观察者 接受的是主题的数据
1、抽象观察者
public interface IObserver {
public void update(String message);
}
2、具体观察者
public class Observer implements IObserver{
private String name;
//不同的观察者,订阅者不同
public Observer(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(this.name+"接受消息:"+message);
}
}
3、抽象主题
import java.util.ArrayList;
import java.util.List;
abstract class Subject {
List<IObserver> list = new ArrayList<IObserver>();
public void attach(IObserver observer) {
list.add(observer);
}
public void detach(IObserver observer) {
list.remove(observer);
}
public void notify(String message) {
for(IObserver observer:list) {
observer.update(message);
}
}
}
4、具体主题
public class ConcreteSub extends Subject{
//notify方法的封装
public void notifyConcrete(String message) {
notify(message);
}
}
5、test测试
public class Test {
public static void main(String[] args) {
ConcreteSub concrete = new ConcreteSub();
Observer observer1 = new Observer("robin");
Observer observer2 = new Observer("xiaoluo");
Observer observer3 = new Observer("罗大");
concrete.attach(observer1);
concrete.attach(observer2);
//不关联observer3,此时无法接受发布的消息
concrete.notify("欢迎订阅");
}
}
robin接受消息:欢迎订阅
xiaoluo接受消息:欢迎订阅
三、pop模式拉取模式
观察者 接受的是主题的引用
1、抽象观察者
public interface IObserver {
public void update(Subject sub);
}
2、具体观察者
public class Observer implements IObserver{
private String name;
//不同的观察者,订阅者不同
public Observer(String name) {
this.name = name;
}
@Override
//接受引用
public void update(Subject sub) {
String message = ((ConcreteSub)sub).getState();
System.out.println(name+"自动拉取数据:"+message);
}
}
3、抽象主题
import java.util.ArrayList;
import java.util.List;
abstract class Subject {
List<IObserver> list = new ArrayList<IObserver>();
public void attach(IObserver observer) {
list.add(observer);
}
public void detach(IObserver observer) {
list.remove(observer);
}
public void notifyOther() {
for(IObserver observer:list) {
observer.update(this);//传入自身引用
}
}
}
4、具体主题
public class ConcreteSub extends Subject{
private String state;
public String getState() {
return state;
}
public void notifyConcrete(String message) {
this.state = message;
this.notifyOther();
}
}
5、test测试
public class Test {
public static void main(String[] args) {
ConcreteSub concrete = new ConcreteSub();
Observer observer1 = new Observer("robin");
Observer observer2 = new Observer("xiaoluo");
Observer observer3 = new Observer("罗大");
concrete.attach(observer1);
concrete.attach(observer2);
concrete.attach(observer3);
concrete.notifyConcrete("更新数据");
}
}
robin自动拉取数据:更新数据
xiaoluo自动拉取数据:更新数据
罗大自动拉取数据:更新数据
四、标准模式(继承现有接口和抽象类)
1、Observal抽象类
(1)拉取,不传输任何数据
public void notifyObservers() {
notifyObservers(null);
}
(2)推送,传输参数
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);//调用update
}
2、具体观察者
import java.util.Observable;
import java.util.Observer;
public class ObserverConcrete implements Observer {
private String name;
//不同的观察者,订阅者不同
public ObserverConcrete(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
String messageString = ((ConcreteSub)o).getState();
System.out.println(name+"标准接口拉取数据:"+messageString);
}
}
2、具体主题
import java.util.Observable;
public class ConcreteSub extends Observable{
private String state;
public String getState() {
return state;
}
public void notifystand(String message) {
this.state = message;
this.setChanged();//设置状态已经改变
this.notifyObservers();//内部调用Observer的update,此时选择的是拉取方式实现,当然可以选择推送方式
}
}
5、test测试
public class Test {
public static void main(String[] args) {
ConcreteSub cocreSub = new ConcreteSub();
ObserverConcrete o1 = new ObserverConcrete("罗大");
ObserverConcrete o2 = new ObserverConcrete("罗二");
ObserverConcrete o3 = new ObserverConcrete("罗三");
cocreSub.addObserver(o1);
cocreSub.addObserver(o2);
cocreSub.addObserver(o3);
cocreSub.notifystand("标准方式推送的数据");
}
}
罗三标准接口拉取数据:标准方式推送的数据
罗二标准接口拉取数据:标准方式推送的数据
罗大标准接口拉取数据:标准方式推送的数据
五、引用
【1】demo参照:https://blog.csdn.net/yanbober/article/details/45484749