在大多数 Android 项目中,UI(Activity / Fragment / ViewModel)直接调用 Repository 看起来很自然:
要数据?找 Repository 要提交?找 Repository
但当项目规模变大后,这种方式几乎一定会引发一个严重问题:
业务逻辑散落
本文通过一个真实复杂业务场景 ,解释什么是业务逻辑散落,以及为什么需要通过 UseCase(Domain 层) 来收敛业务规则。
一、什么是业务逻辑散落
业务逻辑散落指的是:
同一套业务规则,被拆散写在多个 UI / ViewModel / 页面中,各自维护一份。
它的本质不是"代码多",而是:
- 规则不再有唯一实现
- 规则的修改成本呈指数级增长
一旦业务复杂度上来,这会成为项目失控的起点。
二、复杂真实案例:订单价格计算
这是电商 / 会员 / 金融类 App 中最典型、最危险的一类业务。
订单最终价格规则(示例)
订单价格 =
- 商品总价
- − 优惠券
- − 会员折扣
- − 活动折扣
-
- 运费(满额免运费)
-
- 税费(不同地区规则不同)
并且规则是动态变化的:
- 新人优惠
- 黑五 / 双十一活动
- 某些商品不参与折扣
- 会员等级差异
- 国家 / 地区税率
👉 这是一个天然复杂、且会持续演进的业务规则集合。
三、错误做法:UI 直接访问 Repository
当 UI 直接访问 Repository 时,业务规则往往会自然地"扩散"。
商品详情页 ViewModel

购物车页 ViewModel
结算页 ViewModel

看起来每个页面都"合理",但实际上:
价格计算规则已经在 3 个地方产生了 3 种实现。
四、业务变更带来的灾难
几个月后,产品提出新规则:
- 满 100 元免运费
- 某些商品不参与会员折扣
- 优惠券不能和活动折扣叠加
此时你会发现:
- 商品页要改
- 购物车页要改
- 结算页要改
- 还有历史遗留页面也要改
只要漏改一个页面,就会出现线上价格不一致的严重事故。
这就是:
业务逻辑散落的真实代价
在大型 App 中,80% 的"诡异业务 bug"都源于此。
五、正确做法:UseCase 收敛业务规则(Domain 层)
将"价格计算"视为一个完整业务能力,而不是 UI 的临时逻辑。
Domain 层:统一业务入口

UI 层:只消费结果

UI 不再关心:
- 优惠规则
- 叠加逻辑
- 特殊 case
六、这样做带来的直接收益
✅ 业务规则只有一个地方实现 ✅ 所有页面价格天然一致 ✅ 改规则只改一个 UseCase ✅ 单元测试只测 Domain ✅ UI 代码显著变简单
这才是 Clean Architecture 的真正价值。
七、关键认知纠偏(非常重要)
很多人以为:
UI 不访问 Repository,只是为了"分层好看"
这是误解。
真正的核心目的只有一个:
防止复杂业务规则在 UI 层不断复制、扩散、失控
分层只是手段,不是目的。
八、业务逻辑散落的"高危重灾区"
在真实项目中,以下业务极不应该写在 UI:
- 价格 / 费用计算
- 权限判断
- 登录态 / 风控校验
- 提交前校验
- 会员等级规则
- 活动叠加规则
一旦写在 UI,项目规模一上来,必炸。
九、面试标准回答
如果面试官问:
为什么 UI 不建议直接访问 Repository?
推荐回答:
如果 UI 直接访问 Repository,复杂业务规则会在多个页面重复实现,导致业务逻辑散落;通过 UseCase 将业务规则集中在 Domain 层,可以保证规则统一、降低修改成本,并显著提升系统的可维护性和稳定性。
