EventBus源码分析(四):EventBus中的几种设计模式
再看一下EventBus,总结一下其中几个重要的设计模式,也是最常见的几种设计模式:单例模式、建造者模式、观察者模式。多看源码的好处之一就是能从优秀的代码里活学活用。
1、单例模式
单例模式(Singleton Pattern)是设计模式中最简单也是最常见的设计模式。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
通常用一个私有静态变量存储这个唯一的实例,而且有的源码中还会加上volatile关键字修饰:
static volatile EventBus defaultInstance;
类提供了一种访问其唯一的对象的方式,可以直接访问类的实例,不需要再实例化该类的对象。这个方法也是实现单例模式的关键,EventBus中提供getDefault()方法获取全局唯一的EventBus单例,这种单例使用的是双检锁(DCL)方式,实现单例模式的方法参考单例的五种方式一文。
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
有了getDefault()方法,开发者就可以随处随地的获取EventBus实例,进行发送事件、注册订阅者等操作。
EventBus.getDefault().postSticky(new MessageEvent("Hello EventBus"));
而Kotlin提供了更加方便的单例实现,使用object关键词创建实例,见《对象声明:object》一文。
2、建造者模式
建造者模式(Builder Pattern)将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。一个Builder类会一步一步构造最终的对象。该Builder类是独立于其他对象的。
构造EventBus实例就用到了建造者模式,构造EventBus实例的构造方法用到了EventBusBuilder这个构造类。
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
...
}
借助EventBusBuilder类构造配置信息,提供一系列的设置方法。而且这些方法返回建造者自身,可以方便的实现链式调用,对构造对象进行设置的方法调用一气呵成。
/** Default: true */
public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) {
this.logSubscriberExceptions = logSubscriberExceptions;
return this;
}
/** Default: true */
public EventBusBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) {
this.logNoSubscriberMessages = logNoSubscriberMessages;
return this;
}
/** Default: true */
public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) {
this.sendSubscriberExceptionEvent = sendSubscriberExceptionEvent;
return this;
}
/** Default: true */
public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) {
this.sendNoSubscriberEvent = sendNoSubscriberEvent;
return this;
}
...
建造者Builder类通常还会提供一个build()方法,当一切都设置完成,调用该方法生成最终的对象实例。如EventBusBuilder中的build()方法:
/** Builds an EventBus based on the current configuration. */
public EventBus build() {
return new EventBus(this);
}
还可以用EventBusBuilder中的installDefaultEventBus()方法先初始化EventBus库默认的实例:
public EventBus installDefaultEventBus() {
synchronized (EventBus.class) {
if (EventBus.defaultInstance != null) {
throw new EventBusException("Default instance already exists." +
" It may be only set once before it's used the first time to ensure consistent behavior.");
}
EventBus.defaultInstance = build();
return EventBus.defaultInstance;
}
}
借助EventBus中的EventBusBuilder建造者,开发者可以自行定义EventBus行为属性,详见EventBus源码分析(一):构造及订阅一文第1.3节。
3、观察者模式
观察者模式(Observer Pattern)定义了一种一对多的依赖关系,让多个观察者对象同时监听某一对象。当被观察的对象发生修改时,会自动通知所有观察它的对象。观察者模式属于行为型模式。此设计模式最重要的作用就是解耦!将观察者与被观察者解耦,使得它们之间的依赖性更小。
EventBus就是使用了观察者模式,使代码间相互解耦。当发出消息时,通知所有注册的观察者(订阅者)。注册的订阅对象,其实就是观察者。
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
新的事件发送,就通知所有的观察者:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
...
subscriptions = subscriptionsByEventType.get(eventClass);
for (Subscription subscription : subscriptions) {
...
postToSubscription(subscription, event, postingState.isMainThread);
...
}
}
核心关系维护在两个Map映射中:subscriptionsByEventType和typesBySubscriber,详见EventBus源码分析(一):构造及订阅一文第2.1节。
设计模式不是纸上谈兵,曾看过几本关于设计模式的书:《设计模式之禅》、《Head First设计模式》、《大话设计模式》、《Android源码设计模式》等,最大的体会是设计模式属于经验之谈,是前人对于编程的一套经验总结,几十种设计模式硬背倒不难,但要灵活运用,唯手熟尔。
相关博客:
设计模式的六大原则和23种设计模式
单例的五种方式