12.观察者模式

 


12.观察者模式

1.观察者模式

  1. 服务端代码。
public interface Subject {

    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}

public class ConcreteSubject implements Subject {

    private final List<Observer> observers = new ArrayList<>();

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

public interface Observer {

    void update(String message);
}

public class ConcreteObserverOne implements Observer {

    @Override
    public void update(String message) {
        System.out.println(message + "update success for one");
    }
}

public class ConcreteObserverTwo implements Observer {

    @Override
    public void update(String message) {
        System.out.println(message + "update success for two");
    }
}
  1. 客户端代码。
ConcreteSubject subject = new ConcreteSubject();
subject.registerObserver(new ConcreteObserverOne());
subject.registerObserver(new ConcreteObserverTwo());
subject.notifyObservers("hello tom ");

2.观察者模式总结

  1. <<设计模式:可复用面向对象软件的基础>>中对观察者模式的定义:在多个对象之间,定义一个一对多的依赖,当一个对象状态改变时,所有依赖这个对象的对象都会自动收到通知。
  2. 观察者模式是将观察者代码和被观察者代码解耦。

3.观察者案例EventBus

  1. 同步阻塞观察者模式。
public class Observer01 {

    @Subscribe
    public void print(String message) {
        System.out.println(message);
    }
}

public class Observer02 {

    @Subscribe
    public void print(String message) {
        System.out.println(message);
    }
}

/**
 * 同步阻塞观察者模式,EventBus依赖于Guava。
 * 输出 hello hello
 */
public static void test01() {
    EventBus eventBus = new EventBus();
    eventBus.register(new Observer01());
    eventBus.register(new Observer01());
    eventBus.post("hello");
}
  1. 异步阻塞观察者模式。
public class Observer01 {

    @Subscribe
    public void print(String message) {
        System.out.println(message);
    }
}

public class Observer02 {

    @Subscribe
    public void print(String message) {
        System.out.println(message);
    }
}

/**
 * 异步阻塞观察者模式
 */
public static void test02() {
    AsyncEventBus asyncEventBus = new AsyncEventBus(Executors.newFixedThreadPool(10));
    asyncEventBus.register(new Observer01());
    asyncEventBus.register(new Observer02());

    asyncEventBus.post("tom");
}

4.手写EventBus

  1. 服务端。
// 注解的作用范围:方法
@Target(ElementType.METHOD)
// 注解的使用范围:运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
}

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) {
        try {
            method.invoke(target, event);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

public class ObserverRegistry {

    private ConcurrentHashMap<Class<?>, CopyOnWriteArrayList<ObserverAction>> registry = new ConcurrentHashMap<>();

    public void register(Object observer) {
        Map<Class<?>, Collection<ObserverAction>> observerActions = findAllObserverActions(observer);
        for (Map.Entry<Class<?>, Collection<ObserverAction>> entry : observerActions.entrySet()) {
            Class<?> eventType = entry.getKey();
            Collection<ObserverAction> eventActions = entry.getValue();
            CopyOnWriteArrayList<ObserverAction> registeredEventActions = registry.get(eventType);
            if (registeredEventActions == null) {
                registry.putIfAbsent(eventType, new CopyOnWriteArrayList<>());
                registeredEventActions = registry.get(eventType);
            }
            registeredEventActions.addAll(eventActions);
        }
    }

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

    private Map<Class<?>, Collection<ObserverAction>> findAllObserverActions(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> annotateMethods = 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 parameters", method, parameterTypes.length);

                annotateMethods.add(method);
            }
        }
        return annotateMethods;
    }
}

// 同步阻塞观察者模式
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.getMethodObserverActions(event);
        for (ObserverAction observerAction : observerActions) {
            executor.execute(() -> {
                observerAction.execute(event);
            });
        }
    }
}

// 异步阻塞观察者模式
public class AsyncEventBus extends EventBus {
    
    public AsyncEventBus(Executor executor) {
        super(executor);
    }
}
  1. 客户端。
public class Main {

    @Subscribe
    public void demo01(String message) {
        System.out.println(message);
    }

    @Subscribe
    public void demo01(String message, int a) {
        System.out.println(message);
    }

    public static void main(String[] args) {
        EventBus eventBus = new EventBus();
        Main main = new Main();
        eventBus.register(main);
        eventBus.post("hello");
    }
}
posted @   行稳致远方  阅读(18)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示