定义
观察者(Observer)模式 又称发布-订阅模式、模型-视图模式,指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式属于对象行为型模式。
要点
优点:
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
- 目标与观察者之间建立了一套触发机制。
缺点:
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
主要角色:
- 抽象主题(Subject):也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject):也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer):它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer):实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
场景
在哔哩哔哩视频网站上,某UP主被粉丝关注之后,每当UP主更新作品时,订阅该UP主的粉丝账号消息中心会收到相关的提示通知。
实现
AbstractUPSubject
/**
* UP主,相当于抽象主题
*/
public abstract class AbstractUPSubject {
protected String upName;
protected List<FansObserver> fans = new ArrayList<>();
public AbstractUPSubject(String upName) {
this.upName = upName;
}
/**
* 粉丝订阅
*/
public void addFan(FansObserver observer) {
if (observer != null) {
fans.add(observer);
}
}
/**
* 粉丝退订
*/
public void removeFan(FansObserver observer) {
if (observer != null) {
fans.remove(observer);
}
}
/**
* 通知粉丝
*/
public abstract void notifyFans();
}
UPA
/**
* UP主A,相当于具体主题
*/
public class UPA extends AbstractUPSubject {
public UPA(String upName) {
super(upName);
}
@Override
public void notifyFans() {
fans.forEach(fan -> fan.response(upName));
}
}
UPB
/**
* UP主B,相当于具体主题
*/
public class UPB extends AbstractUPSubject {
public UPB(String upName) {
super(upName);
}
@Override
public void notifyFans() {
fans.forEach(fan -> fan.response(upName));
}
}
FansObserver
/**
* 粉丝,相当于抽象观察者
*/
public interface FansObserver {
/**
* 粉丝对订阅通知的响应
*/
void response(String upName);
}
FansA
/**
* 粉丝A,相当于具体观察者
*/
public class FansA implements FansObserver {
private String fanName;
public FansA(String fanName) {
this.fanName = fanName;
}
@Override
public void response(String upName) {
System.out.println(String.format("嗨,【%s】,你关注的UP主【%s】发布了新作品,快来查看吧!", fanName, upName));
}
}
FansB
/**
* 粉丝B,相当于具体观察者
*/
public class FansB implements FansObserver {
private String fanName;
public FansB(String fanName) {
this.fanName = fanName;
}
@Override
public void response(String upName) {
System.out.println(String.format("嗨,【%s】,你关注的UP主【%s】发布了新作品,快来查看吧!", fanName, upName));
}
}
Client
public class Client {
public static void main(String[] args) {
// UP主
AbstractUPSubject upA = new UPA("混世大魔王");
AbstractUPSubject upB = new UPB("樱桃小丸子");
// 粉丝
FansObserver fanA = new FansA("小王");
FansObserver fanB = new FansB("小李");
// 订阅UP主
upA.addFan(fanA);
upA.addFan(fanB);
upB.addFan(fanB);
// 通知
upA.notifyFans();
upB.notifyFans();
}
}
--------------------输出----------------------
嗨,【小王】,你关注的UP主【混世大魔王】发布了新作品,快来查看吧!
嗨,【小李】,你关注的UP主【混世大魔王】发布了新作品,快来查看吧!
嗨,【小李】,你关注的UP主【樱桃小丸子】发布了新作品,快来查看吧!
源码
总结
适用场景:
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
- 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。