为了防止被“杀”了祭天,学点设计模式,并总结下还是有必要的。
一:模式理解
- 观察者模式也可以称为订阅者模式。
- 无论是观察者还是订阅者,关注的是主题的变化。
- 主题发生某些变化时,需要发生通知给所有的观察者和订阅者。
- 观察者和订阅者可以取消对主题的观察或订阅。
- 一些对象需要能感知到一个对象变了(做了某些操作)。假设只有一个主题。
二:例子
你是个富二代,家里有很多仆人。
为了方便,只举例三种,分别是程序员,老司机,女仆。
他们都继承自Servant抽象类,并且都有跪舔的技能,即guitian方法。
public abstract class Servant {
private FuErDai fuErDai;
public Servant(FuErDai fuErDai) {
this.fuErDai = fuErDai;
fuErDai.addServant(this);
}
public void add() {
fuErDai.addServant(this);
}
public void remove() {
fuErDai.fireServant(this);
}
public abstract void guitian();
}
- 每个仆人都有一个fuErDai属性,代表心中时刻都有主人。
- 并且在构造器中直接把自己作为富二代的仆人。
- 富二代比较民主,允许仆人们可以自主决定参加工作或是不干了,分别对应add和remove方法。
- 不同仆人跪舔主人的方法不一样,设置为抽象方法。
分别新建程序员,老司机,女仆三个类。
// 程序员
public class Programmer extends Servant {
public Programmer(FuErDai fuErDai) {
super(fuErDai);
}
@Override
public void guitian() {
System.out.println("表演敲代码!");
}
}
// 老司机
public class Driver extends Servant {
public Driver(FuErDai fuErDai) {
super(fuErDai);
}
@Override
public void guitian() {
System.out.println("老司机开个车让富二代开心开心!");
}
}
// 女仆
public class Maidservant extends Servant {
public Maidservant(FuErDai fuErDai) {
super(fuErDai);
}
@Override
public void guitian() {
System.out.println("如果你追到我,我就和你嘿嘿嘿!");
}
}
作为富二代的你,也有一个对应的类,FuErDai。
public class FuErDai {
private List<Servant> servantList = Lists.newArrayList();
private int happyIndex;
private int healthIndex;
public FuErDai(int happyIndex, int healthIndex) {
this.happyIndex = happyIndex;
this.healthIndex = healthIndex;
}
public void addServant(Servant servant) {
int index = servantList.indexOf(servant);
if (index == -1) {
servantList.add(servant);
}
}
public void fireServant(Servant servant) {
int index = servantList.indexOf(servant);
servantList.remove(index);
}
private void notifyServants() {
for (Servant servant : servantList) {
servant.guitian();
}
}
public void changeIndex(int happyIndex, int healthIndex) {
this.happyIndex = happyIndex;
this.healthIndex = healthIndex;
notifyServants();
}
}
你有三个属性,分别是仆人队列,开心指数,健康指数。
有添加仆人和删除仆人的方法。
在没有观察者模式之前,为了防止你不舒服了或是不开心了,仆人们隔三差五都需要来询问一次。
仆人们发现每次走进你房间的时候,你总是对着蓝天白云的电脑桌面发呆。同时,你也觉得很不开心。
有了观察者模式之后,当你的开心指数或者健康指数变化的时候,就会通知每个仆人,即notifyServants,每个仆人都会前来跪舔你。
public class Client {
public static void main(String[] args) {
FuErDai fuErDai = new FuErDai(100, 100);
Programmer programmer = new Programmer(fuErDai);
Driver driver = new Driver(fuErDai);
Maidservant maidservant = new Maidservant(fuErDai);
fuErDai.changeIndex(100, 90);
System.out.println("--------------");
programmer.remove();
fuErDai.changeIndex(100, 80);
}
}
输入/输出:
表演敲代码!
老司机开个车让富二代开心开心!
如果你追到我,我就和你嘿嘿嘿!
老司机开个车让富二代开心开心!
如果你追到我,我就和你嘿嘿嘿!
可以看到,当你健康指数变化的时候,所有仆人都会前来跪舔。
某天,程序员突然想起之前你答应带他去彻夜鼓掌却一直没再提起,调用了remove方法,不再作为你的仆人。
在你的指数再次变化的时候,程序员将不会来跪舔。
三:再理解
- 在例子中,作为富二代的你就是主题,你的仆人们都是观察者/订阅者。
- 仆人们再也不用轮询来检查你的变化。
- 在通知仆人的方法notifyServants中,可以传参,例子为方便没传递参数。
- 在Java util包中有观察者模式的实现。
- 观察者实现Observer接口,实现update方法;
- 主题继承Observable类,意思为可被观察,底层用Vector<Observer> obs保存所有的观察者,可做到多线程安全;
- 在主题变化时,可调用setChanged()和notifyObservers()方法来通知观察者,观察者们执行update()方法;
- 观察者可通过调用addObserver(this)和deleteObserver(this)方法加入/退出主题的观察者队列。
- Java util自带Observable是个类,主题继承这个类,就不能再继承其他类,不利于扩展。
- 观察者模式中,主题拥有一个观察者列表,观察者又引用了主题。