痛点场景:订单页面的组件纠缠
假设你正在开发一个外卖订单页面,包含:
- 地址选择器
- 优惠券选择器
- 支付方式选择
- 商品列表
- 提交按钮
这些组件需要相互通信:
- 选择地址 → 更新运费 → 刷新总价
- 选择优惠券 → 校验是否适用于当前商品 → 更新折扣 → 刷新总价
- 切换支付方式 → 检查是否支持优惠券 → 更新按钮状态
- 修改商品数量 → 检查库存 → 更新优惠券可用性
传统实现方式(直接引用地狱):
class AddressPicker {
final CouponPicker couponPicker;
final PaymentPicker paymentPicker;
final ProductList productList;
final SubmitButton submitButton;
void onAddressSelected() {
// 更新运费逻辑...
productList.updateShippingFee();
couponPicker.checkApplicability();
paymentPicker.validate();
submitButton.refresh();
}
}
// 其他组件也有类似的交叉引用...
问题爆发点:
- 🕸️ 组件间形成蜘蛛网般的耦合
- 💥 修改一个组件会影响多个其他组件
- 🔥 难以单独测试某个组件
- 🌋 添加新组件需要修改大量现有代码
中介者模式解决方案
核心思想: 用一个中介对象封装一系列对象之间的交互,使各对象不需要显式相互引用,从而使其耦合松散。
四个关键角色:
- 中介者接口(Mediator): 定义通信接口
- 具体中介者(ConcreteMediator): 协调各组件交互
- 同事类(Colleague): 需要通信的组件
- 同事接口(Colleague): 定义组件通用接口(可选)
Flutter订单中介者实现
1. 定义中介者接口
abstract class OrderMediator {
void addressChanged(Address newAddress);
void couponSelected(Coupon? coupon);
void paymentMethodChanged(PaymentMethod method);
void productQuantityChanged(Product product, int quantity);
}
2. 实现具体中介者
class OrderController implements OrderMediator {
final AddressPicker _addressPicker;
final CouponPicker _couponPicker;
final PaymentPicker _paymentPicker;
final ProductList _productList;
final SubmitButton _submitButton;
OrderController({
required AddressPicker addressPicker,
required CouponPicker couponPicker,
// 其他组件...
}) : _addressPicker = addressPicker,
_couponPicker = couponPicker,
// 初始化其他组件...
{
// 设置组件的中介者引用
_addressPicker.mediator = this;
_couponPicker.mediator = this;
// ...
}
void addressChanged(Address newAddress) {
final shippingFee = _calculateShippingFee(newAddress);
_productList.updateShippingFee(shippingFee);
_couponPicker.checkApplicability();
_submitButton.refresh();
}
void couponSelected(Coupon? coupon) {
if (coupon != null && !_productList.isCouponApplicable(coupon)) {
_couponPicker.showError('此优惠券不适用于当前商品');
return;
}
_paymentPicker.validateCoupon(coupon);
_productList.applyCoupon(coupon);
_submitButton.refresh();
}
void paymentMethodChanged(PaymentMethod method) {
if (!method.supportsCoupons && _couponPicker.selectedCoupon != null) {
_couponPicker.clearSelection();
_productList.removeCoupon();
}
_submitButton.refresh();
}
void productQuantityChanged(Product product, int quantity) {
_couponPicker.checkApplicability();
_paymentPicker.validate();
_submitButton.refresh();
}
}
3. 创建同事类(组件)
abstract class OrderComponent {
OrderMediator? mediator;
}
class AddressPicker extends StatefulWidget implements OrderComponent {
OrderMediator? mediator;
_AddressPickerState createState() => _AddressPickerState();
}
class _AddressPickerState extends State<AddressPicker> {
Address? _selectedAddress;
void _handleAddressChange(Address newAddress) {
setState(() => _selectedAddress = newAddress);
widget.mediator?.addressChanged(newAddress);
}
Widget build(BuildContext context) {
return DropdownButton<Address>(
value: _selectedAddress,
items: _buildAddressItems(),
onChanged: _handleAddressChange,
);
}
}
// 其他组件类似实现...
4. 在页面中组装
class OrderPage extends StatefulWidget {
_OrderPageState createState() => _OrderPageState();
}
class _OrderPageState extends State<OrderPage> {
late final OrderMediator _mediator;
void initState() {
super.initState();
final addressPicker = AddressPicker();
final couponPicker = CouponPicker();
// 初始化其他组件...
_mediator = OrderController(
addressPicker: addressPicker,
couponPicker: couponPicker,
// 注入其他组件...
);
}
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
AddressPicker(mediator: _mediator),
CouponPicker(mediator: _mediator),
PaymentPicker(mediator: _mediator),
ProductList(mediator: _mediator),
SubmitButton(mediator: _mediator),
],
),
);
}
}
Flutter中的实际应用场景
场景1:聊天室系统
// 中介者
class ChatRoom implements ChatMediator {
final List<User> _users = [];
void register(User user) {
_users.add(user);
}
void sendMessage(String message, User sender) {
for (final user in _users) {
if (user != sender) {
user.receive(message);
}
}
}
}
// 同事类
class User {
final String name;
final ChatMediator mediator;
User(this.name, this.mediator);
void send(String message) {
print('$name 发送: $message');
mediator.sendMessage(message, this);
}
void receive(String message) {
print('$name 收到: $message');
}
}
// 使用
final chatRoom = ChatRoom();
final john = User('John', chatRoom);
final jane = User('Jane', chatRoom);
chatRoom.register(john);
chatRoom.register(jane);
john.send('Hi there!'); // Jane会收到
jane.send('Hello!'); // John会收到
场景2:表单验证系统
// 中介者
class FormValidator implements FormMediator {
final List<FormField> _fields = [];
void registerField(FormField field) {
_fields.add(field);
}
void validateAll() {
bool isValid = true;
for (final field in _fields) {
if (!field.validate()) {
isValid = false;
}
}
submitButton.setEnabled(isValid);
}
}
// 同事类
class EmailField extends StatefulWidget implements FormField {
FormMediator? mediator;
bool validate() {
// 验证逻辑...
mediator?.validateAll();
}
}
// 在表单中使用
final validator = FormValidator();
EmailField(mediator: validator),
PasswordField(mediator: validator),
SubmitButton(mediator: validator),
场景3:电商筛选系统
// 中介者
class FilterMediator {
final List<FilterWidget> _filters = [];
ProductList? _productList;
void registerFilter(FilterWidget filter) {
_filters.add(filter);
}
void registerProductList(ProductList list) {
_productList = list;
}
void onFilterChanged() {
final filters = _filters.map((f) => f.currentFilter).toList();
_productList?.applyFilters(filters);
}
}
// 使用
final mediator = FilterMediator();
ColorFilter(mediator: mediator),
PriceFilter(mediator: mediator),
BrandFilter(mediator: mediator),
ProductList(mediator: mediator),
中介者模式与状态管理的结合
将中介者与Provider结合:
// 中介者提供者
class OrderMediatorProvider extends ChangeNotifier {
final OrderMediator _mediator;
OrderMediatorProvider(this._mediator);
OrderMediator get mediator => _mediator;
}
// 顶层注册
void main() {
final addressPicker = AddressPicker();
final mediator = OrderController(addressPicker: addressPicker);
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => OrderMediatorProvider(mediator)),
],
child: MyApp(),
),
);
}
// 在组件中使用
Consumer<OrderMediatorProvider>(
builder: (context, provider, child) {
return AddressPicker(mediator: provider.mediator);
}
)
中介者模式最佳实践
何时使用中介者模式:
- 系统中有大量对象需要相互通信
- 对象间引用关系复杂难以理解
- 想定制分布在多个类中的行为又不想生成太多子类
- 通信逻辑需要集中管理
Flutter特化技巧:
// 使用事件总线增强中介者 class EventBusMediator implements OrderMediator { final EventBus _bus; EventBusMediator(this._bus); void addressChanged(Address newAddress) { _bus.fire(AddressChangedEvent(newAddress)); } } // 组件监听事件 _bus.on<AddressChangedEvent>().listen((e) { // 处理地址变更 });
性能优化:
// 懒加载中介者 class LazyMediator implements OrderMediator { OrderController? _controller; void addressChanged(Address newAddress) { _controller ??= OrderController(...); _controller!.addressChanged(newAddress); } }
测试策略:
test('地址变更应更新运费', () { final mediator = MockOrderMediator(); final addressPicker = AddressPicker(mediator: mediator); addressPicker.selectAddress(testAddress); verify(mediator.addressChanged(testAddress)); });
中介者模式 vs 观察者模式
特性 | 中介者模式 | 观察者模式 |
---|---|---|
目的 | 集中管理对象间通信 | 一对多的依赖通知 |
耦合度 | 同事类只认识中介者 | 观察者直接订阅被观察者 |
通信方向 | 可以是双向或多向 | 通常是被观察者→观察者 |
典型应用 | 复杂UI交互、表单系统 | 状态管理、事件处理 |
中介者模式的高级变体
1. 分层中介者
class GlobalMediator {
final List<DomainMediator> _domainMediators = [];
void registerDomain(DomainMediator mediator) {
_domainMediators.add(mediator);
}
void notifyAll(String globalEvent) {
for (final mediator in _domainMediators) {
mediator.handleGlobalEvent(globalEvent);
}
}
}
class OrderMediator implements DomainMediator {
void handleGlobalEvent(String event) {
if (event == 'USER_LOGGED_OUT') {
// 清理订单数据...
}
}
}
2. 中介者+命令模式
abstract class MediatorCommand {
void execute(OrderMediator mediator);
}
class AddressChangeCommand implements MediatorCommand {
final Address newAddress;
AddressChangeCommand(this.newAddress);
void execute(OrderMediator mediator) {
mediator.addressChanged(newAddress);
}
}
// 在组件中使用
void _handleAddressChange(Address newAddress) {
final command = AddressChangeCommand(newAddress);
command.execute(widget.mediator);
}
总结:中介者模式是你的通信枢纽
- 核心价值: 将网状通信结构变为星型结构,降低系统复杂度
- Flutter优势:
- 解耦UI组件
- 集中管理业务逻辑
- 简化组件测试
- 提高代码可维护性
- 适用场景: 复杂表单、电商筛选、聊天系统、多步骤流程
🎛️ 设计启示: 当你发现Flutter组件间有复杂的交叉调用时,中介者模式能帮你理清通信脉络!