You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中MVC与MVVM架构的区别及正确实现问询

Flutter中MVC与MVVM的核心差异及正确实现方式

很多人会误以为MVC和MVVM只是换个类名,但两者的核心逻辑、数据流向和职责划分完全不同,下面结合你做的用户列表场景拆解清楚:

一、核心差异对比

MVC的核心逻辑

  • Controller是「命令执行者」:它直接持有View的引用,既要处理业务逻辑(比如请求用户列表),又要主动触发View更新(比如调用setState或View的刷新方法)。
  • 耦合性高:View和Controller互相依赖,业务逻辑和UI更新代码容易混在一起,后期维护成本高。

MVVM的核心逻辑

  • ViewModel是「数据提供者」:它完全不持有View的引用,只负责暴露可观察的状态(比如用ChangeNotifier、ValueNotifier或Stream),让View自行订阅状态变化。
  • 完全解耦:View只负责UI渲染和用户交互,ViewModel只处理业务逻辑和状态管理,两者通过状态绑定关联,没有直接依赖。

二、从MVC到MVVM的具体改造示例

假设你的MVC用户列表代码大致如下,我们一步步改成标准MVVM:

MVC实现示例

// Model
class User {
  final String id;
  final String name;
  User(this.id, this.name);
}

// Controller
class UserListController {
  // 直接持有View引用
  UserListView? view;
  List<User> users = [];

  Future<void> fetchUsers() async {
    // 模拟网络请求
    await Future.delayed(const Duration(seconds: 1));
    users = [User("1", "张三"), User("2", "李四")];
    // 主动通知View更新
    view?.updateUI();
  }
}

// View
class UserListView extends StatefulWidget {
  @override
  _UserListViewState createState() => _UserListViewState();
}

class _UserListViewState extends State<UserListView> {
  final controller = UserListController();

  @override
  void initState() {
    super.initState();
    // 将View实例传给Controller
    controller.view = this;
  }

  void updateUI() {
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("用户列表")),
      body: ListView.builder(
        itemCount: controller.users.length,
        itemBuilder: (context, index) => ListTile(title: Text(controller.users[index].name)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.fetchUsers,
        child: const Icon(Icons.refresh),
      ),
    );
  }
}

改成MVVM的正确方式

核心是移除ViewModel对View的引用,用可观察状态替代手动调用View更新,这里以ChangeNotifier为例:

// Model 可直接复用,无需修改
class User {
  final String id;
  final String name;
  User(this.id, this.name);
}

// ViewModel
class UserListViewModel extends ChangeNotifier {
  List<User> _users = [];
  // 对外暴露只读的状态
  List<User> get users => _users;

  Future<void> fetchUsers() async {
    await Future.delayed(const Duration(seconds: 1));
    _users = [User("1", "张三"), User("2", "李四")];
    // 通知所有订阅的View更新状态
    notifyListeners();
  }
}

// View
class UserListView extends StatefulWidget {
  @override
  _UserListViewState createState() => _UserListViewState();
}

class _UserListViewState extends State<UserListView> {
  final viewModel = UserListViewModel();

  @override
  Widget build(BuildContext context) {
    // 用Consumer订阅ViewModel的状态变化,自动触发UI更新
    return Scaffold(
      appBar: AppBar(title: const Text("用户列表")),
      body: Consumer<UserListViewModel>(
        builder: (context, vm, child) => ListView.builder(
          itemCount: vm.users.length,
          itemBuilder: (context, index) => ListTile(title: Text(vm.users[index].name)),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: viewModel.fetchUsers,
        child: const Icon(Icons.refresh),
      ),
    );
  }
}

三、关键差异总结

  • 职责边界:MVC的Controller既要处理业务逻辑,又要管理View的更新;MVVM的ViewModel只负责状态和业务,View只负责UI渲染。
  • 耦合程度:MVC中Controller和View互相依赖,修改一方可能影响另一方;MVVM中两者完全独立,ViewModel可复用给不同View。
  • 更新机制:MVC是Controller主动调用View方法更新;MVVM是View订阅状态,自动响应变化。

内容的提问来源于stack exchange,提问作者d3ridi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:22:26