什么是观察者模式
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,时他们能够自动更新自己。
模式角色
- 抽象主题(Star):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
- 具体主题(LuoZhiXiang):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
- Observer抽象观察者(Fan):所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体观察者(ConcreteFan):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
UML类图
![](https://img.haomeiwen.com/i10195209/5b9c172c03ddb916.png)
代码实现
以微博明星为例可以很好解释观察者定义。每个明星(Star)都会有很多粉丝(几十万、几百万、上千万粉丝关注)。粉丝关注着明星的一举一动(粉丝群it是抽象观察者角色),每当明星更新动态那些粉丝就会立马收到消息,点赞的,评论的,控评的,骂人的等等。这里明星Star很明显就是个抽象主题角色,最近很火的明星罗志祥就是具体主题角色的一员。罗志祥发微博上热门后,吃瓜群众会跟风,为后续继续吃瓜关注罗志祥,这就是增加观察者对象,粉丝对罗志祥失望要脱粉,这就是减少观察者对象。粉丝收到通知后点赞,评论这就是在更新了。下面用代码来具体的描述下观察者模式:
public interface Star {
void addFan(Fan fan);
void deleteFan(Fan fan);
void notifyFans(String msg);
}
public class LuoZhiXiang implements Star {
private List<Fan> fanList = new ArrayList<>();
private String starName;
public LuoZhiXiang(String starName) {
this.starName = starName;
}
@Override
public void addFan(Fan fan) {
fanList.add(fan);
}
@Override
public void deleteFan(Fan fan) {
fanList.remove(fan);
}
/**
* 在具体主题内部状态改变时,给所有登记过的观察者发出通知.
* @param msg
*/
@Override
public void notifyFans(String msg) {
fanList.forEach(x -> x.update(msg, starName));
}
}
public interface Fan {
void update(String msg, String starName);
}
public class ConcreteFanA implements Fan {
private String fanName;
public ConcreteFanA(String fanName) {
this.fanName = fanName;
}
@Override
public void update(String msg, String starName) {
System.out.println(fanName + "收到了" + starName + "的微博" + msg);
}
}
public class ConcreteFanB implements Fan {
private String fanName;
public ConcreteFanB(String fanName) {
this.fanName = fanName;
}
// 这个粉丝对idol很失望,说了些不好的言论。罗志祥把他拉黑了。
@Override
public void update(String msg, String starName) {
System.out.println(fanName + "收到了" + starName + "的微博" + msg +"后,评价了罗志祥微博。");
}
}
public class Client {
public static void main(String[] args) {
Fan fanA = new ConcreteFanA("张三");
Fan fanB = new ConcreteFanB("李四");
Star showLo = new LuoZhiXiang( "罗志祥");
showLo.addFan(fanA);
showLo.addFan(fanB);
showLo.notifyFans("道歉小作文");
// 罗志祥就把他拉黑了。
showLo.deleteFan(fanB);
// 被拉黑粉丝,就没办法再实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
showLo.notifyFans("道歉小作文2");
}
}
张三收到了罗志祥的微博道歉小作文
李四收到了罗志祥的微博道歉小作文后,评价了罗志祥微博。
张三收到了罗志祥的微博道歉小作文2
优点
- 观察者模式在被观察者和观察者之间建立一个抽象的耦合。主题角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
- 观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。
缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
- 如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
- 虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
观察者模式完整代码
网友评论