MVC:Model-View-Controller模式的本质及其实现

作者: IT Sectr 发布日期: 2026-02-16 阅读时间: 9 分钟

MVC(Model-View-Controller)——一种架构模式,将应用程序分为三个组件:Model负责数据和业务逻辑,View负责用户界面,Controller负责处理输入以及协调Model和View。在iOS中,MVC通过UIViewController实现,在Android中——通过Activity和Fragment实现。MVC仍然是MVVM、MVP和Clean Architecture所基于的基本模式。更多信息——请参阅MVC in Cocoa Core

要点

  • MVC——三个组件:Model(数据)、View(界面)、Controller(逻辑)
  • UIViewController——iOS中Controller的实现,负责屏幕的生命周期
  • Activity/Fragment——Android中具有类似功能的Controller实现
  • Massive View Controller——MVC的主要问题:控制器膨胀到数千行代码
  • 组件之间的联系——Controller更新View和Model,Model通知Controller更改

什么是MVC:Model-View-Controller模式的本质

MVC(Model-View-Controller)——一种由Trygve Reenskaug于1979年为Smalltalk-80语言提出的架构模式。该模式将应用程序分为三层:Model包含数据和业务逻辑,View负责显示,Controller处理用户输入并更新Model和View。职责分离允许独立更改每一层——例如,将View从UIKit替换为SwiftUI,而无需更改Model中的业务逻辑。

组件的交互在MVC中遵循一个循环:用户与View交互→Controller接收事件→Controller更新Model→Model通知Controller更改→Controller更新View。在经典实现中,Model使用观察者模式:当数据发生变化时,Model发送通知,Controller订阅并更新View。在Apple的实现中,Key-Value Observing(KVO)或NotificationCenter扮演这一角色。

组件职责iOS中的示例Android中的示例
Model数据、业务逻辑、网络Struct User、CoreDataData class、Repository
ViewUI显示Storyboard、XIB、UIViewXML布局、Jetpack Compose
Controller输入处理、协调UIViewControllerActivity、Fragment

MVC在现代移动开发中比10年前使用得更少,但仍然是必须理解的内容。Apple推荐在UIKit应用程序中为简单屏幕使用MVC。Google不推荐在Android中使用纯粹的MVC——官方文档建议使用MVVM与Jetpack。然而,了解MVC对于处理遗留项目和理解架构模式的演变是必要的。

iOS中的MVC:UIViewController和storyboard

Apple MVC——嵌入在UIKit中的模式的自定义实现。UIViewController扮演Controller的角色:管理屏幕的生命周期(viewDidLoad、viewWillAppear、viewDidDisappear),处理触摸和用户操作,通过IBOutlets更新View。View在Interface Builder(storyboard或XIB)中以编程方式创建。Model——任何数据对象:网络服务、CoreData堆栈、Swift结构体。

swift
final class UserViewController: UIViewController {
    // View(通过storyboard outlet)
    @IBOutlet private var nameLabel: UILabel!
    @IBOutlet private var emailLabel: UILabel!

    // Model
    private let userService = UserService()

    override func viewDidLoad() {
        super.viewDidLoad()
        loadUser()
    }

    private func loadUser() {
        userService.fetchUser { [weak self] user in
            // Controller更新View
            self?.nameLabel.text = user.name
            self?.emailLabel.text = user.email
        }
    }
}

Apple MVC的问题——View和Controller紧密耦合。UIViewController同时管理View和逻辑。Storyboard以XML格式存储View,但控制器通过IBOutlets直接引用UI元素。这违反了单一职责原则:控制器负责生命周期、委托、数据源、target-action和动画。结果是,iOS应用的标准屏幕在控制器中包含200–500行代码。

ViewController的生命周期——Apple提供了6个生命周期方法:loadView(手动创建View)、viewDidLoad(View加载到内存后)、viewWillAppear(出现在屏幕之前)、viewDidAppear(动画之后)、viewWillDisappear(离开屏幕之前)、viewDidDisappear(离开之后)。每个方法——在MVC中放置逻辑的地方。将这些方法用于业务逻辑会加速控制器的膨胀。

Android中的MVC:Activity、Fragment和XML布局

Android MVC——Activity和Fragment扮演Controller的角色,XML布局文件——View,任何带有数据的POJO类——Model。Activity管理屏幕的生命周期:onCreate、onStart、onResume、onPause、onStop、onDestroy。Fragment——Activity内的子屏幕,具有自己的生命周期。View(XML)与Controller分离,通过setContentView或LayoutInflater加载。Model——仓库、数据库、网络调用。

kotlin
class UserActivity : AppCompatActivity() {
    // View通过XML布局
    private lateinit var binding: ActivityUserBinding

    // Model
    private val userRepository = UserRepository()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityUserBinding.inflate(layoutInflater)
        setContentView(binding.root)
        loadUser()
    }

    private fun loadUser() {
        userRepository.getUser { user ->
            runOnUiThread {
                binding.nameText.text = user.name
                binding.emailText.text = user.email
            }
        }
    }
}

Android ViewBinding和DataBinding——减少Controller和View耦合的现代工具。ViewBinding生成一个类,直接从XML引用View,消除了findViewById。DataBinding增加了通过@{user.name}在XML标记中将数据与UI绑定的能力。DataBinding——迈向MVVM的一步,因为它允许在没有Activity代码的情况下将数据从Model传输到View。Google推荐所有新项目使用DataBinding。

Android的生命周期比iOS更复杂:Activity可能在屏幕旋转、内存不足或配置更改时被销毁和重新创建。在纯粹的MVC中,控制器(Activity)包含在销毁时会丢失的逻辑。这需要通过onSaveInstanceState或Jetpack中的ViewModel保存状态,这超出了纯粹MVC的框架,使架构更接近MVVM。

Massive View Controller和MVC的局限性

Massive View Controller——描述MVC在移动开发中的主要问题的术语。iOS和Android中的控制器承担了太多职责:输入处理、数据验证、网络交互、导航、缓存、动画、生命周期管理。结果,控制器膨胀到500–2000行代码,变得难以阅读、测试和维护。

Massive View Controller的原因——UIKit和Android Framework的架构鼓励将逻辑放在控制器中。网络调用、JSON处理、导航——所有这些自然地在Activity或UIViewController中编写,因为它们可以访问生命周期和UI。开发人员必须有意识地将逻辑提取到单独的类(Service、Manager、Interactor)中,这需要纪律和对架构原则的理解。

MVC问题描述解决方案
强耦合Controller知道View和ModelMVVM——ViewModel不知道View
测试困难Controller依赖UIKit/Android将逻辑提取到服务中
生命周期状态在旋转时丢失Jetpack/SwiftUI中的ViewModel
缺乏导航Controller管理转场Coordinator模式、Router

MVC的测试——Model通过单元测试进行隔离测试。由于依赖UIKit/UIFoundation,Controller难以测试。XCTest不允许在没有视图窗口的情况下创建UIViewController。对于Android,ActivityTestRule和Robolectric部分解决了问题,但测试速度较慢。View通常不通过单元测试进行测试——UI使用截图测试和UI测试(XCUITest、Espresso)。

何时使用MVC是合理的——包含一两个元素的简单屏幕(登录屏幕、个人资料、设置)。用于验证假设的原型和MVP——MVC无需额外层即可更快编写。代码库小到10–15个屏幕的项目。在复杂项目中,MVC会导致技术债务的积累,并需要每6–12个月进行重构。

MVC与MVVM、MVP和Clean Architecture的比较

MVC vs MVVM——主要区别:在MVVM中,控制器被ViewModel取代,ViewModel没有对View的引用。数据通过Observable(SwiftUI)、LiveData/StateFlow(Android)或Combine/RxSwift传递。ViewModel在没有UI依赖的情况下通过单元测试进行测试。Apple自2019年起推荐MVVM与SwiftUI,Google推荐MVVM与LiveData/Flow作为Android的官方架构。MVVM需要更多代码进行绑定,但显著提高了可测试性。

MVC vs MVP——在MVP(Model-View-Presenter)中,Presenter是一个可测试的层,通过接口接收View。与MVC不同,MVC中Controller直接通过UIKit管理View,而Presenter不依赖于框架——通过ViewInterface抽象工作。MVP在Jetpack出现之前在Android开发中很流行,并用于旧项目。Presenter比Activity存活更久,并在屏幕旋转时保持状态。

MVC vs Clean Architecture——Clean Architecture添加了Use Cases(Interactors)、Entities、Gateways和Repository层。MVC保留在展示层,但业务逻辑被移动到领域层,使用Use Cases。Clean Architecture从根本上解决了Massive View Controller问题——Controller只包含Use Cases调用和View更新。缺点——类和文件数量显著增加,这对于50+个屏幕的项目是合理的。

swift
// iOS中的MVC:Controller包含一切
class OrderViewController: UIViewController {
    func placeOrder() {
        // 验证 + 网络 + UI更新
        guard Validation.isValid(total) else { return }
        NetworkService.shared.submit(order) { [weak self] result in
            self?.handleResult(result)
        }
    }
}

// MVVM:逻辑在ViewModel中
class OrderViewModel: ObservableObject {
    @Published var state: OrderState = .idle
    func placeOrder() { /* 业务逻辑 */ }
}

架构的选择取决于团队规模、项目和所需的可测试性。对于1–2名开发人员的团队和最多20个屏幕的项目,MVVM是合适的。对于5名以上开发人员的大型团队和50个屏幕以上的项目——具有模块化结构的Clean Architecture。MVC仍然具有现实意义用于理解架构的演变、支持遗留项目以及在没有复杂业务逻辑的UIKit中构建简单屏幕。

常见问题

MVC在移动开发中的主要问题是什么?

主要问题是Massive View Controller。在iOS中,UIViewController控制器负责一切:输入处理、更新View、网络工作、导航和生命周期。在Android中,Activity/Fragment执行类似的功能。结果,控制器膨胀到数千行代码,变得难以测试和维护,违反了单一职责原则。

MVC与MVVM有何不同?

在MVC中,控制器直接更新View和处理用户输入。在MVVM中,控制器的角色由ViewModel承担,ViewModel没有对View的引用——数据通过绑定机制传递。MVVM更容易测试,因为ViewModel不依赖于UIKit或Android Framework。Apple推荐MVVM与SwiftUI,Google推荐MVVM与Jetpack Compose。

可以在现代项目中使用MVC吗?

是的,MVC仍然是简单屏幕和原型的工作模式。Apple推荐对具有简单屏幕的UIKit应用程序使用MVC。对于具有多个屏幕、网络请求和缓存的复杂项目,最好选择MVVM、VIPER或Clean Architecture。建议初学者在学习更复杂的模式之前先掌握MVC。

如何测试MVC应用程序?

Model可以隔离测试——它们是普通的数据对象和业务逻辑。由于依赖UIKit或Android Framework,Controller难以测试。建议将业务逻辑从控制器提取到单独的服务或交互器中,这些服务或交互器通过单元测试进行测试。View通常不通过单元测试进行测试——使用UI测试和截图测试。

在MVC之后应该选择哪种模式?

在iOS中——MVVM与SwiftUI和Combine,自2019年以来的Apple标准。在Android中——MVVM与LiveData或StateFlow,Google官方推荐。对于拥有5名以上开发人员团队的大型项目——iOS上使用VIPER的Clean Architecture或Android上按功能划分模块的Clean Architecture。对于使用MVC的遗留项目——逐步重构,将逻辑提取到单独的服务中。

总结

  • MVC——分为Model、View和Controller的架构模式
  • iOS MVC——UIViewController + storyboard + 数据服务
  • Android MVC——Activity/Fragment + XML布局 + 仓库
  • Massive View Controller——职责混杂导致的主要问题
  • 测试——Model易于测试,Controller需要提取逻辑
  • 演进——MVC → MVVM → Clean Architecture用于不断增长的项目
  • 兼容性——模式可以在一个项目中组合使用

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读