移动开发中的SoC:概念、原则与职责分离

作者: IT Sectr 发布日期: 2026-05-13 阅读时间: 8 分钟

SoC(Separation of Concerns)是一项原则的缩写,根据该原则,软件系统被划分为独立的职责领域。根据Martin Fowler的观点,职责分离是可维护代码的关键要素。SoC原则允许开发人员更改应用程序的一个层而不影响其他层,这在团队移动开发中尤为重要。

要点

  • SoC — Separation of Concerns的缩写,表示按职责领域划分代码
  • 缩写用于架构讨论中,表示层独立性原则
  • MVP、MVVM和Clean Architecture — 在iOS和Android项目中实现SoC的模式
  • 层隔离简化了单元测试和开发人员之间的工作并行化
  • 违反SoC导致出现数千行的类,难以维护

缩写SoC的含义

SoC是Separation of Concerns的缩写,意为"职责分离"或"关注点分离"。在编程上下文中,concern一词指任何可分离的功能:用户界面显示、点击处理、数据验证、网络通信或数据库操作。SoC原则要求围绕这些领域对代码进行分组,以便一个领域的更改不会影响其他领域。

SoC缩写广泛应用于技术文献、架构讨论和框架文档中。例如,在Android Architecture Components文档中,多次提到SoC作为分离ViewModel和View的动机。在iOS社区中,该术语用于讨论Massive View Controller问题——缺乏SoC的直接后果。

重要的是要理解SoC不是一次性操作,而是一个持续的过程。随着应用程序的增长,出现新的职责领域,架构需要重新审视。一个良好的代码库在达到每个concern都隔离且可管理的稳定状态之前,会经历多次划分迭代。

SoC与Separation of Concerns

Separation of Concerns及其缩写SoC表示同一原则。区别仅在于使用上下文:全名用于正式文档、教育材料以及首次向新开发人员解释概念时。SoC在技术讨论、代码审查和需要简洁的文档中更方便。

在专业环境中,这两个术语可以互换使用。开发人员可以说"这里违反了SoC"或"这违反了Separation of Concerns"——含义不变。然而,在招聘信息和架构要求中,全名更常见,而在聊天和代码审查中——缩写。了解这两种变体对于顺利进入行业是必要的。

存在术语混淆:SoC缩写也用于硬件上下文中的System-on-a-Chip(片上系统)。在移动开发中,上下文总是从环境中明确的——如果讨论涉及代码架构,则指的是Separation of Concerns。在本文中,SoC始终指职责分离原则。

SoC在移动架构中的应用

三层架构 — 在移动应用中实现SoC的最常见方式。它将代码分为Presentation(UI)、Domain(业务逻辑)和Data(与数据源交互)。每一层包含严格定义的类型类,并通过接口与相邻层隔离。这种方法对iOS、Android和Flutter项目同样有效。

Presentation层和ViewModel

View和ViewModel构成表示层。View负责渲染界面和传递用户事件。ViewModel存储屏幕状态并将来自Domain层的数据转换为准备显示的格式。ViewModel没有对Activity、Fragment或UIViewController的引用——这确保了UI和逻辑之间的SoC。

例如,在Android Jetpack中,ViewModel在屏幕旋转后依然存在,而UI被重新创建。没有SoC,我们将不得不在Activity中存储状态,将生命周期管理与数据混合。ViewModel独立解决这个任务,展示了职责分离原则的纯粹实现。

Domain层和Use Cases

Use Cases包含独立于平台的业务规则。这一层不导入Android SDK、iOS UIKit或Flutter框架。Use Case从Repository接收数据,对其应用业务逻辑,并返回结果。得益于SoC,一个Use Case可以在不同屏幕和平台上重复使用。

经典例子 — 注册表单的ValidateAndSaveUseCase。它检查电子邮件和密码的正确性,调用UserRepository进行保存,并返回ValidationResult。UI和数据库都不知道验证规则——它们集中在一个地方,便于修改。

Data层和Repository

Repository将数据源与应用程序的其余部分抽象开来。ViewModel不知道数据来自哪里——REST API、GraphQL、本地数据库或缓存。Repository决定使用哪个源,并将此逻辑隐藏在接口后面。这是数据获取和消费之间的SoC。

DataSource提供更深入的分离:RemoteDataSource仅负责HTTP请求,LocalDataSource负责与Room、CoreData或SharedPreferences交互。Repository组合它们并应用缓存策略。每个DataSource可以独立替换,这在服务器或数据库之间迁移时至关重要。

这种多层次的DataSource系统在基础设施层面实现了SoC:网络通信、本地存储和缓存——独立的concerns,每个都有自己的逻辑和生命周期。更换HTTP客户端时,只有RemoteDataSource发生变化,而Repository和更高层保持不变,这证实了职责分离的实践价值。

SoC在架构模式中

MVP(Model-View-Presenter)— 最早在移动开发中明确实现SoC的模式之一。Presenter包含逻辑并通过接口管理View。View是被动的——只显示Presenter所说的内容。分离简化了测试:Presenter可以在没有模拟器的情况下测试,而View保持简单以至于不会出错。

MVVM添加了响应式绑定:View通过Observable或StateFlow订阅ViewModel的更改。ViewModel不保留对View的引用,消除了内存泄漏的风险,并更强地分离了concerns。在Android中,MVVM通过Jetpack ViewModel和LiveData成为标准,在iOS中——通过Combine和RxSwift。

Clean Architecture(整洁架构)由Robert Martin提出,将SoC推向环的彻底分离。外环(框架和驱动程序)依赖于内环(实体),但反之则不然。在实践中,移动项目很少实现所有四个环——Presentation周围的Domain和Data层就足够了。但"向内"依赖原则本身在更换框架时提供了显著优势。

swift
// View — 仅显示,不含逻辑
final class LoginViewController: UIViewController {
    let viewModel: LoginViewModel

    func loginTapped() {
        viewModel.login(emailField.text, passwordField.text)
    }
}

// ViewModel — 包含屏幕逻辑,不依赖UIKit
final class LoginViewModel {
    private let loginUseCase: LoginUseCase

    func login(email: String?, password: String?) {
        loginUseCase.execute(email, password)
    }
}

// Use Case — 业务逻辑,不依赖平台
final class LoginUseCase {
    private let repo: AuthRepository

    func execute(email: String?, password: String?) {
        guard let e = email, let p = password else { return }
        repo.authenticate(e, p)
    }
}

示例展示了三个SoC层次:LoginViewController仅传递事件,LoginViewModel管理状态,LoginUseCase包含业务规则。每个类都独立测试,更换UI框架不会影响Use Case。

移动项目中SoC的典型违反

Massive View Controller — iOS中最常见的SoC违反。一个管理UI、处理网络请求、解析JSON和存储数据的类在所有层面上都违反了原则。解决方案——将每个职责提取到单独组件中:NetworkingService、JSONParser、CoreDataStack,只给ViewController留下View管理。

Android中有类似问题——God Activity或God Fragment。一个Activity加载数据、验证表单、显示对话框和更新UI。通过引入ViewModel和Repository来治疗,它们接管状态和数据管理。ViewModel还能防止屏幕旋转时的数据丢失。

第三个违反——混合平台和业务代码。例如,将HTTP请求直接放在SwiftUI View或Android Composable中。这使代码不可移植且难以测试。正确的方法——将请求提取到Repository,通过Use Case调用,View只订阅结果。系统的每个元素解决自己的任务,不超出其边界。

常见问题

SoC和SOLID是一回事吗?

。SoC是将系统划分为职责领域的更通用原则。SOLID是面向对象设计的五个具体规则集。SOLID的第一个原则(单一职责)是SoC在单个类层面上的特殊情况。

如何检查项目中是否遵守SoC?

使用单一变更原因规则(单一职责)。如果一个类因UI更改、数据格式更改和业务规则更改而发生变化——则SoC被违反。ArchTest(Android)和StrictConcurrency(iOS)等工具有助于自动检测此类违反。

SoC是否会降低性能?

理论上,额外的层次增加间接调用,但在实践中,对移动应用性能的影响可以忽略不计。编译器内联许多调用,JIT和AOT优化消除了开销。代码的可维护性获得的收益远大于在抽象上损失的部分。

如何在现有项目中实施SoC?

从将网络请求从UI提取到Repository开始。然后将业务逻辑分离到Use Cases中。使用依赖注入来连接各层。迭代地进行更改,用测试覆盖新代码——这保证了重构不会破坏现有功能。

在原型和MVP中是否需要遵守SoC?

原型中,为了速度可以违反SoC。但如果原型转入产品开发,重构成本可能超过快速启动的好处。最佳做法——即使在原型中也保持最小分离(UI和数据),以免在启动时需要重写所有内容。

总结

  • SoC — Separation of Concerns的缩写,将代码划分为独立职责领域的原则
  • 三层架构(Presentation、Domain、Data)— 在移动开发中实现SoC的标准方式
  • MVP和MVVM — 基于UI和业务逻辑分离的架构模式
  • Clean Architecture将SoC扩展到整个系统层面,将业务实体与框架隔离
  • Massive View Controller — 违反SoC的直接后果,通过层提取解决
  • 依赖注入 — 在SoC实现中维护层之间边界的关键工具
  • 平衡分离与简洁 — 实践中应用SoC的主要规则

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

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

讨论项目

另请阅读