手寫EventBus(觀察者模式、源碼閱讀、反射)

學(xué)習(xí)王爭老師《設(shè)計模式之美》,觀察者模式部分實現(xiàn)了一個簡單的EventBus,太棒了,設(shè)計特別巧妙,其中的解耦思路,運用在自己正在開發(fā)的項目中,大大優(yōu)化原本不好維護(hù)的代碼。在此記錄下,方便回顧與學(xué)習(xí)。

整個小框架的代碼實現(xiàn)包括5個類:
EventBus、AsyncEventBus、Subscribe、ObserverAction、ObserverRegistry。

1. Suscibe

Subscribe 是一個注解,用于標(biāo)明觀察者中的哪個函數(shù)可以接收消息。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Beta
public @interface Subscribe {
}

2. ObserverAction

ObserverAction 類用來表示 @Subscribe 注解的方法,其中,target 表示觀察者類,method 表示方法。它主要用在 ObserverRegistry 觀察者注冊表中。

/**
 * ObserverAction用來表示@Subscribe注解的方法.
 * <p>
 * target表示觀察者類,method表示方法。
 *
 */
public class ObserverAction {
    private Object target;
    private Method method;

    public ObserverAction(Object target, Method method) {
        this.target = target;
        this.method = method;
    }

    public void execute(Object event) { // event 是 method方法的參數(shù)
        try {
            method.invoke(target, event);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

3. ObserverRegister

ObserverRegistry 類就是前面講到的 Observer 注冊表,是最復(fù)雜的一個類,框架中幾乎所有的核心邏輯都在這個類中

public class ObserverRegistry {
    private ConcurrentMap<Class<?>, CopyOnWriteArraySet<ObserverAction>> registry = new ConcurrentHashMap<>();

    public void register(Object observer) {
        Map<Class<?>, Collection<ObserverAction>> observerAction = findAllObserverAction(observer);
        for (Map.Entry<Class<?>, Collection<ObserverAction>> entry : observerAction.entrySet()) {
            Class<?> eventType = entry.getKey();
            Collection<ObserverAction> eventActions = entry.getValue();
            CopyOnWriteArraySet<ObserverAction> observerActions = registry.computeIfAbsent(eventType,
                    e -> new CopyOnWriteArraySet<ObserverAction>());
            observerActions.addAll(eventActions);
        }
    }

    public List<ObserverAction> getMatchedObserverActions(Object event) {
        List<ObserverAction> matchedObservers = new ArrayList<>();
        Class<?> postedEventType = event.getClass();
        for (Map.Entry<Class<?>, CopyOnWriteArraySet<ObserverAction>> entry : registry.entrySet()) {
            Class<?> eventType = entry.getKey();
            if (eventType.isAssignableFrom(postedEventType)) {
                matchedObservers.addAll(entry.getValue());
            }
        }
        return matchedObservers;
    }

    private Map<Class<?>, Collection<ObserverAction>> findAllObserverAction(Object observer) {
        Map<Class<?>, Collection<ObserverAction>> observerActions = new HashMap<>();
        Class<?> clazz = observer.getClass();
        for (Method method : getAnnotateMethods(clazz)) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            Class<?> eventType = parameterTypes[0];
            if (!observerActions.containsKey(eventType)) {
                observerActions.put(eventType, new ArrayList<>());
            }
            observerActions.get(eventType).add(new ObserverAction(observer, method));
        }
        return observerActions;
    }

    private List<Method> getAnnotateMethods(Class<?> clazz) {
        List<Method> annotatedMethods = new ArrayList<>();
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Subscribe.class)) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                Preconditions.checkArgument(parameterTypes.length == 1,
                        "Method %s has @Subscribe annotation but has %s parameters." + "Subscriber methods must have exactly 1 parameter.",
                        method, parameterTypes.length);
                annotatedMethods.add(method);
            }
        }
        return annotatedMethods;
    }
}

4. EventBus

public class EventBus {
    private Executor executor;
    private ObserverRegistry registry = new ObserverRegistry();

    public EventBus() {
        this(MoreExecutors.directExecutor());
    }

    protected EventBus(Executor executor) {
        this.executor = executor;
    }

    public void register(Object object) {
        registry.register(object);
    }

    public void post(Object event) {
        List<ObserverAction> observerActions = registry.getMatchedObserverActions(event);
        for (ObserverAction observerAction : observerActions) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    observerAction.execute(event);
                }
            });
        }
    }
}

5. AsyncEventBus

public class AsyncEventBus extends EventBus {

    public AsyncEventBus(Executor executor) {
        super(executor);
    }
}

演示Demo

public class DemoUserService {

    private EventBus eventBus;

    public DemoUserService() {
        eventBus = new EventBus();
    }

    /**
     * 添加觀察者.
     *
     * @param observers
     */
    public void setRegObservers(List<Object> observers) {
        for (Object observer : observers) {
            eventBus.register(observer);
        }
    }

    /**
     * 注冊用戶,觸發(fā)動作。
     * @param phone
     * @param password
     */
    public Long register(String phone, String password) {
        // 注冊用戶。。。
        Long userId = 1L; // 注冊返回用戶id

        eventBus.post(userId);

        return userId;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 上文中,講了觀察者模式的原理、實現(xiàn)、應(yīng)用場景,重點介紹了不同應(yīng)用場景下,幾種不同的實現(xiàn)方式,包括:同步阻塞、異步非...
    舍是境界閱讀 700評論 0 1
  • 一、觀察者模式的定義在對象之間定義一個一對多的依賴,當(dāng)一個對象狀態(tài)改變的時候,所有依賴的對象都會自動收到通知。該模...
    熊本極客閱讀 423評論 0 1
  • 本文EventBus源碼基于3.1.1版本 前言 ? EventBus是Android開發(fā)最常使用到的通信框架...
    Joe_blake閱讀 360評論 0 1
  • 觀察者模式 - 發(fā)布訂閱模式 1. 什么是觀察者模式 在對象間建立一個"一對多"的依賴. 當(dāng)一個對象的狀態(tài)發(fā)生變化...
    lj72808up閱讀 243評論 0 0
  • 1、觀察者模式概述: 觀察者模式(Observer Pattern):定義對象之間的一種一對多依賴關(guān)系,使得每當(dāng)一...
    Tifkingsly閱讀 697評論 1 0

友情鏈接更多精彩內(nèi)容