目录
-
- 核心结论
- 一、逐个定义(从底层到上层)
-
- [1. 委托(Delegate)](#1. 委托(Delegate))
- [2. 事件(Event)](#2. 事件(Event))
- [3. 发布-订阅模式(Publish-Subscribe/PubSub)](#3. 发布-订阅模式(Publish-Subscribe/PubSub))
- 二、三者层级&从属关系
- 三、关键对比(易混淆点)
-
- [1. 委托 vs 事件](#1. 委托 vs 事件)
- [2. 事件 vs 发布-订阅](#2. 事件 vs 发布-订阅)
- [3. 委托≠发布-订阅](#3. 委托≠发布-订阅)
- [四、完整运行逻辑(C# 点击事件示例)](# 点击事件示例))
- 五、其他语言对应关系
- 六、极简背诵总结
- [Java 实现基于委托+事件思想的发布-订阅(标准版)](#Java 实现基于委托+事件思想的发布-订阅(标准版))
-
- 场景
-
- [1. 订单事件对象(继承EventObject)](#1. 订单事件对象(继承EventObject))
- [2. 事件监听器接口(模拟委托,继承EventListener)](#2. 事件监听器接口(模拟委托,继承EventListener))
- [3. 发布者(订单服务)](#3. 发布者(订单服务))
- [4. 订阅者实现](#4. 订阅者实现)
- [5. 测试主类](#5. 测试主类)
- 运行结果
- C#与Java关键对应
- 核心设计要点
- 拓展方向
- [Java 纯手动实现(无继承EventObject/EventListener)](#Java 纯手动实现(无继承EventObject/EventListener))
-
- [1. 纯事件数据类(无继承)](#1. 纯事件数据类(无继承))
- [2. 纯函数式监听器接口(无继承)](#2. 纯函数式监听器接口(无继承))
- [3. 发布者(逻辑不变)](#3. 发布者(逻辑不变))
- [4. 订阅者+测试(支持Lambda)](#4. 订阅者+测试(支持Lambda))
- 无继承版优势
- 通用泛型事件总线简化版
核心结论
委托是语言层面的语法/类型基础,事件是基于委托封装的安全通信机制,发布-订阅(观察者模式)是设计思想/架构模式,事件是发布-订阅在C#等主流面向对象语言里最典型的落地实现。
一、逐个定义(从底层到上层)
1. 委托(Delegate)
- 定位:C# 特有语言级「方法指针/函数容器」,Java 无原生委托,用接口替代
- 本质:引用类型,用于存储、传递签名匹配的方法
- 作用:解耦调用方与执行方,支持动态挂载方法
- 特点:支持多播;无业务语义、无安全限制,外部可直接赋值、清空、调用
2. 事件(Event)
- 定位:基于委托封装的受保护消息通知机制,C# 关键字,依赖委托实现
- 底层:委托的语法糖+访问权限控制
- 核心约束:仅定义类内部可触发;外部仅支持
+=订阅、-=取消订阅 - 语义:专用于「动作发生时通知所有订阅者」
3. 发布-订阅模式(Publish-Subscribe/PubSub)
- 定位:GoF 观察者模式,通用架构思想,跨语言
- 角色:发布者(主题/Subject)推送消息;订阅者(观察者/Observer)接收并处理
- 核心:完全解耦,双方仅依赖统一通知接口
- 分类:进程内(UI事件、组件回调);分布式(RabbitMQ、Kafka、Redis PubSub)
二、三者层级&从属关系
- 层级从低到高:委托(语言基础)→ 事件(委托安全封装)→ 发布-订阅(设计模式)
- 委托是地基:C# 事件依赖委托实现
- 事件是委托安全增强版:锁住权限,仅开放订阅/取消订阅
- 事件是进程内发布-订阅标准实现:C# 中
event定义+内部触发+外部+=完全匹配观察者模式
一句话串联:C# 用委托做方法回调,用事件做权限封装,用事件落地进程内发布-订阅模式
三、关键对比(易混淆点)
1. 委托 vs 事件
| 维度 | 委托(Delegate) | 事件(Event) |
|---|---|---|
| 关系 | 事件底层类型 | 基于委托封装 |
| 访问权限 | 外部可赋值、调用、清空 | 仅内部可触发,外部仅 +=/-= |
| 语义 | 通用方法容器 | 专用于消息通知 |
| 场景 | 通用函数传递、简单回调 | UI事件、组件通知、发布订阅 |
csharp
// 委托定义
public delegate void MsgDelegate(string msg);
// 裸委托
public MsgDelegate NormalDelegate;
// 事件
public event MsgDelegate MsgEvent;
2. 事件 vs 发布-订阅
- 范畴:发布-订阅是设计思想;事件是C#语法实现
- 范围:发布-订阅覆盖进程内+分布式;C#事件仅限当前进程/AppDomain
- 实现:纯观察者手动维护列表;C#事件由编译器自动维护
3. 委托≠发布-订阅
委托仅为方法载体,仅封装为「订阅+通知」结构时才构成发布-订阅
四、完整运行逻辑(C# 点击事件示例)
- 预定义
ClickEventHandler委托(约定签名) Button类定义event ClickEventHandler Click- 订阅者用
button.Click += OnButtonClick订阅 - 点击时按钮内部触发事件
- 所有订阅方法依次执行
流程:委托定签名 → 事件做权限封装 → 构成发布-订阅模式
五、其他语言对应关系
- Java:无委托,用接口(Observer/Listener)替代,手动维护订阅集合
- JavaScript:函数一等公民等价委托,
addEventListener等价事件 - C++:函数指针/仿函数≈委托,手动封装事件机制
六、极简背诵总结
- 委托:C# 存放方法的底层工具
- 事件:委托加权限控制,专用于消息通知
- 发布-订阅:解耦通知的设计思想
- 关系:事件基于委托,是C#进程内发布-订阅标准实现
Java 实现基于委托+事件思想的发布-订阅(标准版)
场景
订单创建后通知库存扣减、短信发送、日志记录
1. 订单事件对象(继承EventObject)
java
import java.util.EventObject;
public class OrderCreatedEvent extends EventObject {
private final String orderId;
private final String userId;
private final double amount;
public OrderCreatedEvent(Object source, String orderId, String userId, double amount) {
super(source);
this.orderId = orderId;
this.userId = userId;
this.amount = amount;
}
public String getOrderId() { return orderId; }
public String getUserId() { return userId; }
public double getAmount() { return amount; }
}
2. 事件监听器接口(模拟委托,继承EventListener)
java
import java.util.EventListener;
@FunctionalInterface
public interface OrderCreatedListener extends EventListener {
void onOrderCreated(OrderCreatedEvent event);
}
3. 发布者(订单服务)
java
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class OrderService {
private final List<OrderCreatedListener> listeners = new CopyOnWriteArrayList<>();
// 订阅(+=)
public void addOrderCreatedListener(OrderCreatedListener listener) {
if (listener != null) listeners.add(listener);
}
// 取消订阅(-=)
public void removeOrderCreatedListener(OrderCreatedListener listener) {
if (listener != null) listeners.remove(listener);
}
// 私有触发(仅内部可调用)
private void fireOrderCreatedEvent(OrderCreatedEvent event) {
for (OrderCreatedListener listener : listeners) {
try {
listener.onOrderCreated(event);
} catch (Exception e) {
System.err.println("事件处理异常:" + e.getMessage());
}
}
}
// 业务方法
public void createOrder(String orderId, String userId, double amount) {
System.out.println("【订单服务】创建订单成功,订单ID:" + orderId);
fireOrderCreatedEvent(new OrderCreatedEvent(this, orderId, userId, amount));
}
}
4. 订阅者实现
java
// 库存服务
public class InventoryService implements OrderCreatedListener {
@Override
public void onOrderCreated(OrderCreatedEvent event) {
System.out.println("【库存服务】扣减库存,订单ID:" + event.getOrderId());
}
}
// 短信服务
public class SmsService implements OrderCreatedListener {
@Override
public void onOrderCreated(OrderCreatedEvent event) {
System.out.println("【短信服务】发送短信给用户:" + event.getUserId());
}
}
// 日志服务
public class LogService implements OrderCreatedListener {
@Override
public void onOrderCreated(OrderCreatedEvent event) {
System.out.println("【日志服务】记录订单:" + event.getOrderId() + ",金额:" + event.getAmount());
}
}
5. 测试主类
java
public class PubSubDemo {
public static void main(String[] args) {
OrderService orderService = new OrderService();
InventoryService inventory = new InventoryService();
SmsService sms = new SmsService();
LogService log = new LogService();
orderService.addOrderCreatedListener(inventory);
orderService.addOrderCreatedListener(sms);
orderService.addOrderCreatedListener(log);
System.out.println("===== 第一次创建订单 =====");
orderService.createOrder("ORDER_20240520_001", "USER_1001", 99.9);
System.out.println("\n===== 取消短信订阅 =====");
orderService.removeOrderCreatedListener(sms);
System.out.println("\n===== 第二次创建订单 =====");
orderService.createOrder("ORDER_20240520_002", "USER_1002", 199.9);
}
}
运行结果
===== 第一次创建订单 =====
【订单服务】创建订单成功,订单ID:ORDER_20240520_001
【库存服务】扣减库存,订单ID:ORDER_20240520_001
【短信服务】发送短信给用户:USER_1001
【日志服务】记录订单:ORDER_20240520_001,金额:99.9
===== 取消短信订阅 =====
===== 第二次创建订单 =====
【订单服务】创建订单成功,订单ID:ORDER_20240520_002
【库存服务】扣减库存,订单ID:ORDER_20240520_002
【日志服务】记录订单:ORDER_20240520_002,金额:199.9
C#与Java关键对应
| C# 概念 | Java 实现 | 说明 |
|---|---|---|
| delegate 委托 | 函数式监听器接口 | 统一方法签名契约 |
| event 事件 | List<监听器>+add/remove | 维护订阅列表 |
| 事件触发 | 私有fireXXX方法 | 仅发布者内部可调用 |
| 多播委托 | 遍历列表调用 | 手动实现多播 |
核心设计要点
- 解耦:发布者与订阅者仅依赖接口与事件对象
- 线程安全:
CopyOnWriteArrayList - 异常隔离:单个订阅者异常不影响整体
- 数据只读:事件仅提供getter
- 权限控制:触发方法私有
拓展方向
泛型事件、异步处理、事件总线、事件优先级
Java 纯手动实现(无继承EventObject/EventListener)
1. 纯事件数据类(无继承)
java
public class OrderCreatedEvent {
private final String orderId;
private final String userId;
private final double amount;
private final Object source;
public OrderCreatedEvent(Object source, String orderId, String userId, double amount) {
this.source = source;
this.orderId = orderId;
this.userId = userId;
this.amount = amount;
}
public String getOrderId() { return orderId; }
public String getUserId() { return userId; }
public double getAmount() { return amount; }
public Object getSource() { return source; }
}
2. 纯函数式监听器接口(无继承)
java
@FunctionalInterface
public interface OrderCreatedListener {
void onOrderCreated(OrderCreatedEvent event);
}
3. 发布者(逻辑不变)
java
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class OrderService {
private final List<OrderCreatedListener> listeners = new CopyOnWriteArrayList<>();
public void addListener(OrderCreatedListener listener) {
if (listener != null) listeners.add(listener);
}
public void removeListener(OrderCreatedListener listener) {
if (listener != null) listeners.remove(listener);
}
private void fireOrderCreatedEvent(OrderCreatedEvent event) {
for (OrderCreatedListener listener : listeners) {
try {
listener.onOrderCreated(event);
} catch (Exception e) {
System.err.println("事件处理异常:" + e.getMessage());
}
}
}
public void createOrder(String orderId, String userId, double amount) {
System.out.println("【订单服务】创建订单成功,订单ID:" + orderId);
fireOrderCreatedEvent(new OrderCreatedEvent(this, orderId, userId, amount));
}
}
4. 订阅者+测试(支持Lambda)
java
// 传统订阅者
public class InventoryService implements OrderCreatedListener {
@Override
public void onOrderCreated(OrderCreatedEvent event) {
System.out.println("【库存服务】扣减库存,订单ID:" + event.getOrderId());
}
}
public class LogService implements OrderCreatedListener {
@Override
public void onOrderCreated(OrderCreatedEvent event) {
System.out.println("【日志服务】记录金额:" + event.getAmount());
}
}
// 测试类
public class PurePubSubDemo {
public static void main(String[] args) {
OrderService orderService = new OrderService();
InventoryService inventory = new InventoryService();
LogService log = new LogService();
orderService.addListener(inventory);
orderService.addListener(log);
// Lambda订阅
orderService.addListener(event ->
System.out.println("【短信服务】发送给:" + event.getUserId())
);
System.out.println("===== 第一次创建订单 =====");
orderService.createOrder("ORDER_001", "USER_1001", 99.9);
System.out.println("\n===== 取消库存订阅 =====");
orderService.removeListener(inventory);
System.out.println("\n===== 第二次创建订单 =====");
orderService.createOrder("ORDER_002", "USER_1002", 199.9);
}
}
无继承版优势
- 代码纯粹,无多余依赖
- 完美支持Lambda
- 无Java标准事件模型限制
- 学习成本低,灵活度高
通用泛型事件总线简化版
java
@FunctionalInterface
public interface EventListener<T> {
void onEvent(T event);
}
public class EventPublisher<T> {
private final List<EventListener<T>> listeners = new CopyOnWriteArrayList<>();
public void addListener(EventListener<T> listener) {
if (listener != null) listeners.add(listener);
}
public void removeListener(EventListener<T> listener) {
if (listener != null) listeners.remove(listener);
}
public void fireEvent(T event) {
for (EventListener<T> listener : listeners) {
try {
listener.onEvent(event);
} catch (Exception e) {
System.err.println("事件处理异常:" + e.getMessage());
}
}
}
}