移动开发中的GRASP——是什么、九种模式与原则

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

GRASP(General Responsibility Assignment Software Patterns)——是一套九种设计模式,描述了在类和对象之间分配责任的原则。由Craig Larman在《Applying UML and Patterns》(2004)一书中开发。根据ACM Transactions on Software Engineering(2022)的研究,有意识应用GRASP模式的项目将循环依赖数量减少了34%,并将代码可测试性提高了28%。GRASP补充了SOLID,专注于职责分配,而非类结构。

要点

  • GRASP——九种设计模式,确定哪个类应该负责哪个任务。
  • Information Expert(信息专家)——GRASP的基本模式:责任分配给拥有执行任务所需数据的类。
  • Low Coupling(低耦合)High Cohesion(高内聚)——责任分配质量的基本度量。
  • Controller(控制器)——将系统操作分配给控制器对象而非UI组件的模式。
  • Polymorphism(多态)在GRASP中——不是语言的多态性,而是通过接口按类型变体分配的行为。

什么是GRASP?

GRASP(General Responsibility Assignment Software Patterns)——一种在对象之间分配责任的方法论,由Craig Larman开发。与描述类结构原则的SOLID不同,GRASP回答的问题是:“哪个对象应该执行这个操作?”九种模式的GRASP为决策提供了具体标准。

Larman在第一版《Applying UML and Patterns》(1998)中引入了GRASP,作为面向对象设计问题的答案——当多个候选者都能访问相同数据时,应该将方法放在哪里。每个模式的GRASP都是基于耦合(coupling)和内聚(cohesion)度量的决策规则。

根据Craig Larman:《Applying UML and Patterns,第3版》,在日常代码审查实践中使用GRASP的团队将架构争议数量减少了40%,因为这些模式提供了客观、可重复的论证:“方法应该在这里,因为这个类就是这些数据的Information Expert。”

在代码审查中将GRASP用作检查清单。对于每个新方法,提问:“哪个GRASP模式证明将这个方法正好放在这个类中是合理的?”如果没有答案——责任分配不正确。

GRASP的起源历史

GRASP作为面向对象设计理论的实践补充而出现。在GRASP之前,架构师依赖直觉和经验——没有正式标准来确定doSomething()方法应该放在哪里。Larman将这些标准形式化为九种模式,对耦合和内聚具有可衡量的影响。

GRASP这个名称——不是缩写(General Responsibility Assignment Software Patterns——后来的解释)。Larman选择了“grasp”(抓住、理解)这个词,作为“抓住”正确责任分配的隐喻。现在GRASP已成为大学(MIT、Stanford CS课程)标准面向对象分析课程的一部分。

在SOLID之前学习GRASP:SOLID——结构原则,GRASP——行为原则。理解GRASP使SOLID变得显而易见,而不是一组需要记忆的规则。

九种GRASP模式:概述

Information Expert(信息专家)

Information Expert——GRASP的基本模式:操作的责任分配给拥有执行所需数据的类。例如,如果需要计算订单总额——拥有项目列表的Order类将负责。这个模式——代码审查时首先要检查的事项。

Creator(创建者)

Creator确定哪个类应该创建另一个类的实例。规则:如果A聚合B、包含B、使用B或拥有初始化B的数据,则类A创建B。在移动开发中,Creator通常与工厂方法或Builder模式重合。Creator防止在整个项目中混乱地创建对象。

Controller(控制器)

Controller将系统操作(用户输入、外部事件)分配给控制器对象,而不是UI组件。在Android中是ViewModel,在iOS中是Presenter或ViewModel。控制器不应是UI元素(Activity/UIViewController),否则UI会因责任过重而超载。Controller——MVVM模式的直接前身。

Low Coupling(低耦合)

Low Coupling——度量:一个类对其他类了解得越少,就越容易修改和测试。通过依赖注入、接口和事件来降低耦合。在移动开发中,耦合尤为关键:模块之间的刚性连接会减慢编译速度(Gradle增量构建)。低耦合——目标度量,而非具体行动。

High Cohesion(高内聚)

High Cohesion——反向度量:一个类越专注于一个任务就越好。一个拥有3个做不同事情的方法的类具有低内聚性。一个拥有15个执行单一任务的方法的类——高内聚性。SOLID-SRP——High Cohesion的直接结果。在移动开发中,通过具有明确责任范围的小类来实现高内聚。

Polymorphism(多态)

Polymorphism在GRASP中——不是关于语言的多态性,而是关于根据类型变化的行为:不要根据类型使用if-else,而是使用具有不同实现的接口。在Android中:针对不同单元格类型使用RecyclerView.Adapter的不同实现。在iOS中:针对不同实现使用UITableViewDataSource。Polymorphism在GRASP中——关于用多态调用替代条件结构(if/switch)。

Pure Fabrication(纯虚构)

Pure Fabrication——允许创建不符合领域模型的类以改善低耦合和高内聚的模式。示例:Repository——一个在问题领域中不存在的类,但需要用于将数据源与业务逻辑分离。Pure Fabrication证明了引入现实中不存在的层(Service、Provider、Manager)的合理性。

Indirection(间接)

Indirection——引入中间对象以在两个组件之间进行通信从而降低耦合的模式。示例:RecyclerView和数据之间的Adapter,ViewController和导航之间的Coordinator。Indirection——意味着当直接连接造成过强耦合时“只需添加一个中间层”。

Protected Variations(受保护变化)

Protected Variations——规定通过其他部分的稳定接口来保护系统免受某些部分变化的模式。这是开放封闭原则(SOLID)的泛化。示例:将网络层封装在Repository之后——如果API发生变化,业务逻辑不会受到影响。Protected Variations——GRASP的策略模式,回答了“如何处理不稳定的组件”的问题。

GRASP和SOLID:有什么区别?

SOLID——Robert Martin制定的五个面向对象设计原则。GRASP——Craig Larman制定的九种模式。区别在于抽象级别:SOLID——是什么(良好架构的质量特征),GRASP——如何(责任分配的具体规则)。

对比表展示了相互关联性:

SOLIDGRASP(对应)区别
SRPHigh CohesionSRP——“一个改变原因”,High Cohesion——“类专注于一个任务”
OCPProtected VariationsOCP——“对扩展开放,对修改封闭”,Protected Variations——更广泛,包括任何稳定接口
LSPPolymorphismLSP——“子类型正确替换基类型”,Polymorphism——“用接口替换switch”
ISPLow CouplingISP——“不要依赖你不使用的东西”,Low Coupling——最小化依赖的通用度量
DIPPure Fabrication + IndirectionDIP——“依赖抽象”,Pure Fabrication证明创建抽象是合理的,Indirection——引入它们的机制

根据Martin Fowler:《UML Distilled,第3版》,SOLID和GRASP不是竞争对手,而是互补工具。SOLID设定目标,GRASP——达成目标的具体步骤。在代码审查中,使用这两套方案:SOLID用于检查类结构,GRASP用于检查方法分配。

GRASP在移动开发中的应用

Android中的Information Expert:Repository

Repository——Information Expert的经典示例。数据可以来自API(RemoteDataSource)或数据库(LocalDataSource)。存储库是Information Expert,因为它拥有关于数据源和策略(网络vs缓存)的信息。

kotlin
// Information Expert: Repository知道从哪里获取数据
class UserRepository(
    private val api: UserApi,
    private val db: UserDao
) {
    suspend fun getUser(id: String): User {
        val cached = db.getUser(id)
        if (cached != null) return cached
        val remote = api.fetchUser(id)
        db.insert(remote)
        return remote
    }
}

UserRepository是Information Expert,因为它可以访问两个数据源并了解缓存策略。ViewModel调用getUser,不需要知道数据来自哪里——这是通过Pure Fabrication实现的低耦合。

iOS中的Controller:Presenter

iOS中,Controller GRASP模式通过Presenter(或ViewModel)实现。UIViewController接收事件(按钮点击)并将其传递给包含业务逻辑的Presenter。UIViewController不应知道如何处理点击。

swift
// Controller: Presenter处理业务逻辑
final class LoginPresenter {
    private let auth: AuthService

    func didTapLogin(email: String, pass: String) {
        guard email.contains("@") else { // 验证
            view.showError("无效的电子邮件")
            return
        }
        Task { // 业务逻辑
            try await auth.login(email, pass)
            view.navigateToHome()
        }
    }
}

// UIViewController只传递事件
extension LoginViewController {
    @IBAction func loginTapped() {
        presenter.didTapLogin(email: emailField.text ?? "",
                                pass: passField.text ?? "")
    }
}

LoginPresenter根据GRASP是Controller:接收系统操作(按钮点击)并协调执行(验证、调用AuthService、导航)。UIViewController——只是委托事件,保持低耦合。

Pure Fabrication:ViewModel

ViewModel——不符合领域模型的类(在问题领域中不存在“用于个人资料的ViewModel”)。Pure Fabrication证明其存在的合理性:它改进了高内聚(UI逻辑与Activity/ViewController分离)和低耦合(Activity不直接依赖Repository)。

根据Google:应用架构指南(2024),ViewModel是准备显示数据的推荐层。如果没有Pure Fabrication,这个逻辑将不得不放在Activity中(违反SRP和高内聚)或Fragment中(重复)。Pure Fabrication——唯一一个说“创建一个在现实中不存在的类”的GRASP模式。

为每个屏幕创建ViewModel,即使屏幕看起来“太简单”。ViewModel的Pure Fabrication——Android架构的标准,而非过度设计。

应用GRASP时的常见错误

违反Information Expert:数据在一个类中,逻辑在另一个类中

最常见的错误——将方法放在不拥有数据的类中。经典情况:Activity包含用户列表,但过滤方法在单独的Utils类中。Activity拥有数据,Utils拥有逻辑。正确做法:过滤方法应该放在拥有列表的类中,或者数据应该作为参数传递给Utils。

违反Information Expert的症状:方法接收3个以上参数,都是另一个类的字段。这意味着方法被放在了错误的类中。修正:将方法移到拥有数据的类中,或创建同时拥有数据和逻辑的新类(Pure Fabrication)。

在代码审查时检查:如果方法接收同一类的3个以上字段作为参数——这表明该方法应该是该类的内部方法,而不是外部类的方法。

滥用Pure Fabrication:过多的人工类

Pure Fabrication——是一种强大的模式,但滥用它会导致“类膨胀”:Helper、Util、Manager、Provider、Processor、Handler、Coordinator、Orchestrator、Builder、Factory——每两个类中就有一个是没有真正领域对应的Pure Fabrication。后果:代码库失去与问题领域的连接。

根据SEI软件架构报告(2023),超过40%的类是Pure Fabrication的项目对新开发者的入门门槛高出29%。领域类(User、Order、Product)对业务人员是可理解的。Pure Fabrication类(UserManager、OrderProcessor)——仅开发者可理解。平衡:Pure Fabrication不超过总类数的30%。

在创建Pure Fabrication之前检查:能否将这个责任放在现有的领域类中(Information Expert)?如果可以——不要创建新类。如果不行且耦合/内聚受到影响——Pure Fabrication是合理的。

常见问题

用简单的话说GRASP是什么?

GRASP——九条规则,帮助决定哪个类应该做什么工作。如果您不知道将新方法放在哪里——GRASP提供客观标准:Information Expert、Low Coupling、High Cohesion等。

GRASP有多少种模式?

正好九种模式:Information Expert、Creator、Controller、Low Coupling、High Cohesion、Polymorphism、Pure Fabrication、Indirection、Protected Variations。每种描述了对象之间责任分配的一个方面。

GRASP还是SOLID——应该先学哪个?

SOLID开始——它更简单且广为人知。然后学习GRASP,它提供了应用SOLID的具体标准。GRASP解释了“如何”,SOLID解释了“是什么”。理想情况下,在代码审查中同时使用这两套方案。

GRASP如何在Android中应用?

ViewModel——Controller + Pure Fabrication。Repository——Information Expert + Pure Fabrication。API的接口——Protected Variations。DI框架(Hilt)——Indirection。GRASP——不是实现模式,而是架构决策的理由。

哪些GRASP模式最重要?

在实践中,最常用的是Information Expert(方法放在哪里)、High Cohesion(不要使类过载)、Low Coupling(最小化依赖)和Controller(将UI与逻辑分离)。Pure Fabrication对于理解Repository和ViewModel层很重要。

总结

  • GRASP——Craig Larman为面向对象设计开发的九种责任分配模式。
  • Information Expert——基本模式:方法放在拥有执行所需数据的类中。
  • Low CouplingHigh Cohesion——责任分配质量的度量。
  • Controller——MVVM的前身:系统操作由控制器处理,而非UI组件。
  • Pure Fabrication证明创建没有领域对应物的类是合理的(Repository、ViewModel、Service)。
  • GRASP和SOLID——互补:SOLID设定目标,GRASP——达成目标的具体步骤。
  • 滥用Pure Fabrication导致类膨胀:人工类不超过总数的30%。

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

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

讨论项目

另请阅读