观察者模式
报社(Subject) 和订阅者(Observer)
观察者模式,就是 观察者Observer
去关注Subject
,然后当Subject
发生数据改变的时候,能将关注它的观察者的数据全部改变。
主题Subject
必须实现的接口
public interface Subject {
/**
* 注册新的观察者
* @param o
*/
void addObserver(Observer o);
/**
* 注销原有的观察者
* @param o
*/
void removeObserver(Observer o);
/**
* 通知所有观察者,数据更新
*/
void notifyObservers();
}
观察者Observer
必须实现的接口
public interface Observer {
/**
* 观察者更新
* 当Subject去Notify所有观察者的时候,就是去调用观察者的update方法
*/
void update(/*里面应该放置参数,但是参数类型和个数,应该随着不同需求而改变*/);
}
自定义实现
java中虽然有包可以实现观察者模式,但是我们也要自己实现一下
这里,我们的业务是实现出版商和订阅者的关系,出版商信息更新的时候,会去提醒订阅者,信息更新
Subject
接口
public interface Subject {
/**
* 注册新的观察者
* @param o
*/
void addObserver(Observer o);
/**
* 注销原有的观察者
* @param o
*/
void removeObserver(Observer o);
/**
* 通知所有观察者,数据更新
*/
void notifyObservers();
}
Observer
接口
public interface Observer {
/**
* 观察者更新
* 当Subject去Notify所有观察者的时候,就是去调用观察者的update方法
* private String info;
* private float price;
* private int nums;
*/
public void update(String info, Float price, Integer nums);
}
- 实现
Subject
接口的出版商Republication
public class Republication implements Subject{
private String info;
private float price;
private int nums;
private List<Observer> observers=new ArrayList<Observer>();
@Override
public void addObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int index = observers.indexOf(o);
observers.remove(index);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(info,price,nums);
}
}
public void measureChanged() {
notifyObservers();
}
public void setInfo(String info) {
this.info = info;
}
public void setPrice(float price) {
this.price = price;
}
public void setNums(int nums) {
this.nums = nums;
}
}
- 实现
Observer
接口的订阅者Customer
public class Customer implements Observer{
private String info;
private float price;
private int nums;
/**
* 不需要无参构造,
* 因为其信息的更新,仰赖与Subject的信息更新
*/
@Override
public void update(String info, Float price, Integer nums) {
if (info!=null) {
this.info=info;
}
if (price!=null) {
this.price=price;
}
if (nums!=null) {
this.nums=nums;
}
}
/**
* 观察者自带的方法
* 显示更新后的信息
*/
public void display() {
System.out.println(this.toString()+"\n\n");
}
@Override
public String toString() {
return "Customer{" +
"info='" + info + '\'' +
", price=" + price +
", nums=" + nums +
'}';
}
}
- 测试
public class ObserverTest {
@Test
public void OBTest() {
Republication rep = new Republication();
Customer c1 = new Customer();
Customer c2 = new Customer();
Customer c3 = new Customer();
//注册观察者
rep.addObserver(c1);
rep.addObserver(c2);
rep.addObserver(c3);
rep.setInfo("这是出版社第一次出版");
rep.setNums(10);
rep.setPrice(12f);
//发生了更改
rep.measureChanged();
c1.display();
c2.display();
c3.display();
//===========================
rep.setInfo("这是出版社的第二次出版");
rep.measureChanged();
c1.display();
c2.display();
c3.display();
}
}
能够发现,所有订阅者的信息,都会更具出版商的信息进行更改:
Java包实现
类和接口介绍
Observer
接口
Observer对象需要实现这个接口
仅有一个update()
方法
Subject
对象在更新的时候,会将自己传进去,从而方便观察者更新自己的信息
class clazz implements Observer {
@Override
public void update(Observable o, Object arg) {
}
}
Observable
类
Subject对象需要继承这个类
该类中存在一个Vector
,用于承载高并发情况下,观察者的存入
源代码量不多,放过来看一看
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
//不直接遍历vector,而是将vector中的值传入数组中,进而进行改变
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/**
* 不传参删除观察者的话,就是删除所有观察者
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
/**
* 在要通知所有观察者之前,一定要setChanged()
* 因为通知观察者之前,会去查看标志位
* private boolean changed = false;
*/
protected synchronized void setChanged() {
changed = true;
}
//取消变化
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
//统计当前观察者数量
public synchronized int countObservers() {
return obs.size();
}
}
实例
还是拿我们之前的例子来举
Republiction2
主体类
对于观察者中update()
方法的调用,根本不用我们操心
因为,在Observanle
中,已经将实体传入update()
中,
到时候在观察者对象中,再拿 主体类 的数据更新自己就好了
public class Republication2 extends Observable {
private String info;
private float price;
private int nums;
public void measureChanged() {
/**
* 一定要调用setChanged方法
* 因为Observable方法中设定了标志位
* 只有通过setChanged()方法,将标志位设置为true
* 才会去选择更新观察者的信息
*/
setChanged(); //!!!
notifyObservers();
}
public void setInfo(String info) {
this.info = info;
}
public void setPrice(float price) {
this.price = price;
}
public void setNums(int nums) {
this.nums = nums;
}
public String getInfo() {
return info;
}
public float getPrice() {
return price;
}
public int getNums() {
return nums;
}
}
Consumer2
观察者
需要实现
public class Customer2 implements Observer {
private String info;
private float price;
private int nums;
/**
* Subject在更新Observer的时候
* 会传入自身
* 从而方便Observer根据Subject来更新自己的数据
* @param o Subject传入的自身
* @param arg 参数,如果没有的话,subject会传入null
*/
@Override
public void update(Observable o, Object arg) {
if (o instanceof Republication2) {
Republication2 rep = (Republication2) o;
this.info=rep.getInfo();
this.price=rep.getPrice();
this.nums=rep.getNums();
}
}
public void display() {
System.out.println(this.toString()+"\n");
}
@Override
public String toString() {
return "Customer2{" +
"info='" + info + '\'' +
", price=" + price +
", nums=" + nums +
'}';
}
}
- 测试
@Test
public void OBTest2() {
Republication2 rep = new Republication2();
Customer2 c1 = new Customer2();
Customer2 c2 = new Customer2();
Customer2 c3 = new Customer2();
//注册观察者
rep.addObserver(c1);
rep.addObserver(c2);
rep.addObserver(c3);
rep.setInfo("这是出版社第一次出版");
rep.setNums(10);
rep.setPrice(12f);
//发生了更改
rep.measureChanged();
c1.display();
c2.display();
c3.display();
//===========================
rep.setInfo("这是出版社的第二次出版");
rep.measureChanged();
c1.display();
c2.display();
c3.display();
//===========================
rep.deleteObserver(c2);
rep.setInfo("这是出版社的第三次出版");
rep.measureChanged();
c1.display();
c2.display();
c3.display();
}
自定义实现和java包实现的优劣对比
因为util
包下的Observable
是一个类,所以主体想要实现,必须要进行继承操作
这违背了我们多用组合,少用继承
的原则
而且因为java不支持多继承,所以这个主体难以扩展
(我个人还认为,使用继承,必须要对源码比较的熟悉,不然,其中的诸多方法,使用起来都是云里雾里)
所以如果java包可以很好的实现我们的功能,那就用吧
如果不能,那就自己实现吧