Flutter开发实战:中介者模式(Mediator Pattern)

170 阅读6分钟

中介者模式(Mediator Pattern)是一种行为设计模式,其主要目的是降低多个类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理所有类之间的通信,这样各类不需要互相引用,从而使其耦合性降低,同时提高了代码的可读性和可维护性。

中介者模式的主要参与者有

  1. 中介者(Mediator): 定义了一个接口,用于与各同事对象通信。
  2. 具体中介者(Concrete Mediator): 实现中介者接口并协调各同事对象。
  3. 同事类(Colleague): 定义了各同事类的接口。
  4. 具体同事类(Concrete Colleague): 实现同事类的接口,它需要知道中介者对象,以便与其他同事通信。

中介者模式.svg

适用场景

  1. 系统中对象之间存在大量的紧密耦合。
  2. 想定制一个分布在多个类中的行为,但又不想生成太多的子类。

下面让我们一起来看一下,如何在Flutter中使用中介者模式(Mediator Pattern)来简化开发。

场景一:聊天应用

一个聊天室,每个用户都可以发送消息,而不需要知道其他用户的存在。聊天室作为中介者,负责接收和广播消息。

  • 创建一个中介者接口ChatMediator,定义了同事对象之间的通信协议。
  • 具体的中介者ChatRoom实现了消息的广播机制。
  • 每个用户作为同事对象ChatUser,知道如何发送消息并接收来自中介者的消息。
// Mediator
abstract class ChatMediator {
  void sendMessage(String msg, ChatUser user);
  void addUser(ChatUser user);
}

// ConcreteMediator
class ChatRoom implements ChatMediator {
  List<ChatUser> users = [];

  @override
  void addUser(ChatUser user) {
    users.add(user);
  }

  @override
  void sendMessage(String msg, ChatUser user) {
    for (var u in users) {
      // Message should not be relayed back to the sender
      if (u != user) {
        u.receive(msg);
      }
    }
  }
}

// Colleague
abstract class ChatUser {
  void send(String message);
  void receive(String message);
}

// ConcreteColleague
class ChatMember implements ChatUser {
  String name;
  ChatMediator? chatMediator;

  ChatMember(this.name, this.chatMediator) {
    chatMediator?.addUser(this);
  }

  @override
  void send(String message) {
    chatMediator?.sendMessage(message, this);
  }

  @override
  void receive(String message) {
    print('$name received: $message');
  }
}

class ChatApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => ChatAppState();
}

class ChatAppState extends State<ChatApp> {
  ChatMediator? mediator;
  ChatUser? john;
  ChatUser? jane;
  @override
  void initState() {
    super.initState();
    mediator = ChatRoom();
    john = ChatMember("John", mediator);
    jane = ChatMember("Jane", mediator);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Mediator Pattern in Chat')),
        body: Center(
          child: Column(
            children: [
              ElevatedButton(
                onPressed: () => john?.send("Hi Jane!"),
                child: const Text('John sends message'),
              ),
              ElevatedButton(
                onPressed: () => jane?.send("Hi John! How are you?"),
                child: const Text('Jane sends message'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChatApp();
  }
}

void main() => runApp(MyApp());
  • ChatMediator 是中介者接口,定义了同事对象之间的通信协议。
  • ChatRoom 是具体的中介者,负责将消息从一个用户传递给其他所有用户。
  • ChatUser 是同事类接口,定义了用户需要实现的方法。
  • ChatMember 是具体的同事类,每个用户都是一个ChatMember的实例。

通过按下按钮,模拟了John和Jane发送消息的场景。

场景二:注册表单

一个注册表单,其中有多个字段如用户名、密码和电子邮件。当用户输入数据时,每个字段都会进行验证。我们可以使用中介者模式来协调这些验证,当所有字段都有效时,激活提交按钮。

  • FormMediator 中介者负责整个表单的验证。
  • FormField每个字段作为同事对象,知道如何验证自己并通知中介者进行整体验证。
  • 当所有的字段都通过验证时,中介者会激活提交按钮。
// Mediator
abstract class FormMediator {
  void validateForm();
  void addColleague(FormFieldColleague colleague);
}

// ConcreteMediator
class RegisterFormMediator implements FormMediator {
  final List<FormFieldColleague> colleagues = [];
  final Function(bool) onFormValidationChanged;

  RegisterFormMediator(this.onFormValidationChanged);

  @override
  void addColleague(FormFieldColleague colleague) {
    colleagues.add(colleague);
  }

  @override
  void validateForm() {
    bool isFormValid = colleagues.every((colleague) => colleague.isValid);
    onFormValidationChanged(isFormValid);
  }
}

// Colleague
abstract class FormFieldColleague {
  bool get isValid;
  void onFieldChanged();
}

// ConcreteColleague
class FormField extends StatefulWidget {
  final FormMediator mediator;
  final TextInputType keyboardType;
  final String labelText;
  final String? Function(String?) validator;

  FormField({
    required this.mediator,
    required this.labelText,
    this.keyboardType = TextInputType.text,
    required this.validator,
  });

  @override
  _FormFieldState createState() => _FormFieldState();
}

class _FormFieldState extends State<FormField> implements FormFieldColleague {
  final TextEditingController _controller = TextEditingController();
  bool _isValid = false;

  @override
  bool get isValid => _isValid;

  @override
  void initState() {
    super.initState();
    widget.mediator.addColleague(this);
    _controller.addListener(onFieldChanged);
  }

  @override
  void onFieldChanged() {
    setState(() {
      _isValid = widget.validator(_controller.text) == null;
      widget.mediator.validateForm();
    });
  }

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: _controller,
      keyboardType: widget.keyboardType,
      decoration: InputDecoration(labelText: widget.labelText),
      validator: widget.validator,
    );
  }
}

class RegistrationForm extends StatefulWidget {
  @override
  _RegistrationFormState createState() => _RegistrationFormState();
}

class _RegistrationFormState extends State<RegistrationForm> {
  bool _isFormValid = false;

  late final FormMediator mediator;

  @override
  void initState() {
    super.initState();
    mediator = RegisterFormMediator((isValid) {
      setState(() {
        _isFormValid = isValid;
      });
    });
  }

  String? _validateNotEmpty(String? value) {
    return value?.isEmpty == true ? 'Field is required' : null;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Registration Form with Mediator')),
        body: Padding(
          padding: const EdgeInsets.all(15.0),
          child: Column(
            children: <Widget>[
              FormField(
                mediator: mediator,
                labelText: "Username",
                validator: _validateNotEmpty,
              ),
              FormField(
                mediator: mediator,
                labelText: "Email",
                keyboardType: TextInputType.emailAddress,
                validator: _validateNotEmpty,
              ),
              FormField(
                mediator: mediator,
                labelText: "Password",
                keyboardType: TextInputType.visiblePassword,
                validator: (value) {
                  if (value?.isEmpty == true) {
                    return 'Password is required';
                  } else if ((value?.length ?? 0) < 6) {
                    return 'Password should be at least 6 characters';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: _isFormValid ? _submitForm : null,
                child: const Text('Register'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _submitForm() {
    print("Form submitted!");
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RegistrationForm();
  }
}

void main() => runApp(MyApp());
  • RegisterFormMediator 是中介者,负责验证整个表单。
  • 每个 FormField 是一个同事,它知道如何验证自己并通知中介者进行整体验证。
  • 当所有的字段都通过验证时,提交按钮会被激活。

将表单验证的逻辑与每个字段的具体验证逻辑分离,使得代码更加清晰、易于维护。

总结

中介者模式是一种行为设计模式,它的核心思想是通过引入一个单独的中介对象,来封装一系列对象之间的交互和通信。这样,对象之间不再直接相互通信,而是通过中介者对象来协调。这有助于减少系统中各对象之间的依赖关系,使得系统更加模块化,也更易于维护和扩展。

特点

  1. 解耦:中介者模式的主要目的是减少多个类之间的耦合,这样单个类的修改不会影响其他类。
  2. 集中化:所有的交互逻辑都被集中和封装在中介者对象中。
  3. 灵活性:增加新的同事类或者修改现有的交互逻辑,只需要更改中介者对象。

应用

  1. 聊天室:一个聊天室应用中,每个用户可以发送消息,但不需要知道其他用户的具体存在。聊天室(中介者)负责接收每个用户的消息并广播给所有其他用户。这样,用户之间的交互被简化,每个用户只需要与聊天室交互。

  2. 表单验证:一个具有多个输入字段的注册表单。每当用户修改一个字段,都需要进行实时验证。通过使用中介者,每个字段通知中介者其状态是否有效。中介者再根据所有字段的状态决定是否激活提交按钮。

优势

  • 降低耦合:中介者模式确保对象不直接相互通信,而是通过中介者进行交互,这降低了系统中对象之间的依赖。
  • 集中控制交互:由于交互逻辑集中在中介者对象中,更改或扩展交互逻辑变得更加简单。

挑战

  • 中介者的复杂性:随着系统规模的增长,中介者对象可能会变得非常复杂,这可能会导致维护困难。
  • 性能问题:过度使用中介者可能会导致性能问题,因为所有的交互都需要通过中介者进行。

结论

中介者模式为处理对象之间的交互提供了一种非常有效的方法,尤其是当交互变得复杂时。但它也引入了新的挑战,特别是在中介者对象变得非常庞大和复杂时。在实际应用中,应该根据实际需求和场景权衡是否使用中介者模式。

希望对您有所帮助谢谢!!!****