12.观察者模式
12.观察者模式
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");
}
}
- 客户端代码。
ConcreteSubject subject = new ConcreteSubject();
subject.registerObserver(new ConcreteObserverOne());
subject.registerObserver(new ConcreteObserverTwo());
subject.notifyObservers("hello tom ");
2.观察者模式总结
- <<设计模式:可复用面向对象软件的基础>>中对观察者模式的定义:在多个对象之间,定义一个一对多的依赖,当一个对象状态改变时,所有依赖这个对象的对象都会自动收到通知。
- 观察者模式是将观察者代码和被观察者代码解耦。
3.观察者案例EventBus
- 同步阻塞观察者模式。
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");
}
- 异步阻塞观察者模式。
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
- 服务端。
// 注解的作用范围:方法
@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);
}
}
- 客户端。
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");
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端