點燈坊

失くすものさえない今が強くなるチャンスよ

Flutter 使用 MVC 架構分離 UI 與邏輯

Sam Xiao's Avatar 2024-11-04

雖然 Flutter 是以 Dart 寫 UI 與 邏輯,但我們依然可使用 MVC 架構將 UI 與 邏輯 分離,方便日後維護。

Version

Flutter 3.24

Flutter

mvc01

  • Android 與 iOS 都成功使用 MVC 架構分離 UI 與 邏輯

MVC

mvc02

  • controllers
    • 放置所有 controller
    • 檔名以 view 結尾,如 home_view.dart,class 為 HomeView
  • views
    • 放置所有 view
    • 檔名以 controller 結尾,如 home_controller.dart,class 為 HomeController

View

views/home_view.dart

import 'package:flutter/material.dart';

part '../controllers/home_controller.dart';

class HomeView extends StatefulWidget {
  const HomeView({super.key});

  
  State<HomeView> createState() => _HomeView();
}

class _HomeView extends HomeController {
  
  Widget build(BuildContext context) {
    var appBar = AppBar(
      title: const Text('Counter'),
    );

    var floatingActionButton = FloatingActionButton(
      onPressed: _increment,
      child: const Icon(Icons.add),
    );

    var body = Center(
      child: Text('$_count'),
    );

    return Scaffold(
      appBar: appBar,
      floatingActionButton: floatingActionButton,
      body: body,
    );
  }
}

Line 12

class _HomeView extends HomeController {
  
  Widget build(BuildContext context) {
    var appBar = AppBar(
      title: const Text('Counter'),
    );

    var floatingActionButton = FloatingActionButton(
      onPressed: _increment,
      child: const Icon(Icons.add),
    );

    var body = Center(
      child: Text('$_count'),
    );

    return Scaffold(
      appBar: appBar,
      floatingActionButton: floatingActionButton,
      body: body,
    );
  }
}
  • View 只剩下 UI,不包含 邏輯

Line 3

part '../controllers/home_controller.dart';
  • 使用 part 綁定 Controller

Line 12

class _HomeView extends HomeController {
}
  • View 繼承 自 Controller

Line 19

var floatingActionButton = FloatingActionButton(
  onPressed: _increment,
  child: const Icon(Icons.add),
);
  • onPress():所綁定的 increment() 定義於 Controller 而非 View

Controller

controllers/home_controller.dart

part of '../views/home_view.dart';

abstract class HomeController extends State<HomeView> {
  var _count = 0;

  void _increment() {
    setState(() => _count++);
  }
}
  • Controller 只剩下 邏輯,不包含 UI

Line 1

part of '../views/home_view.dart';
  • 使用 part of 綁定於 View

Line 3

abstract class HomeController extends State<HomeView> {
  • Controller 僅為 abstract class,將在 View 中被 繼承

Line 4

var _count = 0;

void _increment() {
  setState(() => _count++);
}
  • State 與 Method 都定義於 Controller

Conclusion

  • Flutter 使用 Dart 寫 UI 後,UI 與 邏輯 合而為一,在小專案時尚可,但在中大型專案時會造成單一檔案有太多代碼的隱患,使用 MVC 架構可將 UI 與 邏輯 分離,方便日後維護

  • 拜 Dart 的 partpart of 語法,將原本單一檔案的 View 拆成兩個檔案的 View 與 Controller,但對於 Flutter 而言,仍視為同一個檔案,只是邏輯上寫成兩個檔案而已

Reference

Leonidas Kanellopoulos, A Simple way to organize your code in Flutter