漂亮的使用协议

71 阅读5分钟

我现在做金融 App 的组件化重构,正好处于需要用“协议优先、服务解耦”思维的阶段。


📚 1️⃣ 什么是“协议优先,服务解耦”?

✅ 协议优先(Protocol First)

核心思想

  • 先定义好“接口协议”Protocol / Interface / API) → 再实现功能
  • 调用方(UI / 上层逻辑)只依赖接口,不依赖具体实现
  • 具体实现可以替换、升级、扩展,调用方无需改动

👉 重点是“先设计接口” → “后实现功能” → 保证灵活性和解耦


✅ 服务解耦(Service Decoupling)

核心思想

  • 各模块 / 各服务之间通过接口交互,不直接依赖彼此内部细节
  • 模块内部变化 → 不影响其它模块
  • 可以独立开发、独立测试、独立发布

🎯 2️⃣ 举个简单例子(结合金融 App)


传统耦合代码(不解耦):

// UI 层直接 new Service,并调用内部方法
let macdCalculator = MACDCalculator()
let result = macdCalculator.calculate(data: stockData)

问题:

❌ UI 直接依赖 MACDCalculator 具体实现 ❌ 如果你后面要换计算逻辑 → UI 要改代码 → 耦合严重


协议优先 + 服务解耦版本:

// 定义协议
protocol IndicatorService {
    func calculateMACD(data: [StockData]) -> MACDResult
}

// 提供实现
class DefaultIndicatorService: IndicatorService {
    func calculateMACD(data: [StockData]) -> MACDResult {
        // 计算逻辑
    }
}

// UI 层依赖协议,不关心实现细节
let indicatorService: IndicatorService = DefaultIndicatorService()
let result = indicatorService.calculateMACD(data: stockData)

优势:

✅ UI 只依赖 IndicatorService 协议,不管具体实现是 DefaultMock、还是别的版本

✅ 后续可以换实现(比如切换到更高性能算法 / 不同行情源) → UI 无需改动

✅ 方便做单元测试 → 可以注入 MockIndicatorService


🚀 3️⃣ 这种思想如何用在组件化重构中?


我现在要做的:

IndicatorKit

MarketModule

RealtimeQuoteModule

👉 都需要“协议优先”思路来设计组件 API


应用场景示意:


✅ IndicatorKit:

protocol IndicatorService {
    func calculateMACD(data: [StockData]) -> MACDResult
    func calculateRSI(data: [StockData]) -> RSIResult
}

然后:

class DefaultIndicatorService: IndicatorService { ... }
class OptimizedIndicatorService: IndicatorService { ... } // 优化版

✅ MarketModule:

protocol MarketDataProvider {
    func fetchMarketList() async -> [MarketItem]
    func fetchStockDetail(stockId: String) async -> StockDetail
}

实现:

class DefaultMarketDataProvider: MarketDataProvider { ... }
class JinStrategyMarketDataProvider: MarketDataProvider { ... } // 换行情源

✅ RealtimeQuoteModule:

protocol RealtimeQuoteService {
    func startQuote(for stockId: String)
    func stopQuote(for stockId: String)
    var onQuoteUpdate: ((QuoteData) -> Void)? { get set }
}

📌 4️⃣ 为什么值得借鉴 MCP 思维?

MCP 协议的核心目标:

✅ 定义 标准协议(比如统一 LLM 接口)

✅ 让前端 / 工具 只依赖协议,不依赖模型实现

✅ 支持插拔不同模型(GPT、Claude、Gemini


组件化也是类似目标:

✅ 定义 标准组件 API(协议)

✅ 上层 UI 只依赖协议,不关心组件实现

✅ 支持插拔不同行情源、不同指标算法

→ 完全通用的设计思想!


📈 5️⃣ 总结成一句话

👉 “协议优先,服务解耦” = 先设计接口(协议),让模块之间低耦合、可替换、可扩展

👉 MCP 思维可以启发组件化的开发:组件 API 应该是「清晰、标准化」的协议,不能“写着写着”直接绑死具体实现!


🎁 6️⃣ 实际操作(可以直接用在现有金融 App 组件化里)

✅ 给 IndicatorKit / MarketModule / RealtimeQuoteModule 都先设计 Protocol + Model(数据结构)

UI 层只通过 Protocol 调用 → 后面行情 SDK 可以替换 → 算法可以优化 → 甚至做 A/B test 都可以

✅ 多人协作也更容易(定义好协议,前端 / 后端 / 算法可以并行开发)



协议(接口)设计

✅ 1️⃣ 协议是不是接口?

是的,本质就是“接口”,英文里通常叫:

  • Protocol(Swift)
  • Interface(Java、Kotlin)
  • 抽象类 / Interface(C++)
  • API 协议(服务接口 / HTTP API 也叫协议)

简单理解协议/接口 = 只定义“要做什么”,不定义“怎么做”


✅ 2️⃣ 协议(接口)定义了什么?

  • 定义了一组“能力 / 方法签名”
  • 谁实现了这个协议 → 谁就具备这个能力
  • 谁调用协议 → 只知道这个能力,不知道谁在实现它

✅ 3️⃣ 为什么协议重要?

👉 解耦调用方与实现方

👉 提升可扩展性

👉 方便测试 / 替换 / 复用


✅ 4️⃣ 协议在哪里实现?

协议定义通常放在“对外开放”的地方,比如:

  • 组件里对外的 API 层IndicatorKit 提供 IndicatorService 协议)
  • Module 对外的接口层MarketModule 提供 MarketDataProvider 协议)

实现通常在组件内部实现,比如:

class DefaultIndicatorService: IndicatorService {
    // 实现协议定义的方法
}

然后 UI / 其它模块只依赖协议,不关心你是不是 Default 实现,或者后期是不是换个实现。


✅ 5️⃣ 怎么理解一个“好的协议”?

👉 核心口诀“只暴露必要能力,隐藏实现细节”


📚 通俗比喻 1️⃣ —— 遥控器

遥控器(协议):
- 打开电视
- 关掉电视
- 调音量
- 换频道

用户(调用方)只需要遥控器协议 → 不需要知道电视内部电路怎么实现。

电视厂商可以换实现(更换芯片 / 算法),遥控器不用换。

📚 通俗比喻 2️⃣ —— 电源插头(协议)

插头(协议)定义:
- 电压
- 电流
- 接口形状

插座(调用方)不关心你后面是啥品牌电饭煲 → 只要符合协议,插上就能用。

✅ 6️⃣ 软件里什么是“好协议”?

好协议坏协议
只暴露核心能力暴露太多实现细节
方法命名清晰、意图明确方法复杂、参数乱
稳定性高,不易频繁改协议改动频繁,影响调用方
易扩展,可替换实现实现和调用方强耦合

✅ 7️⃣ 结合我现在的金融 App 组件化时怎么设计好协议?

IndicatorKit

protocol IndicatorService {
    func calculateMACD(data: [StockData]) -> MACDResult
    func calculateRSI(data: [StockData]) -> RSIResult
}

👉 好协议示例:

✅ 不暴露算法细节

✅ 数据结构清晰

✅ UI 只需要拿到 MACDResultRSIResult 用于图表绘制 → 不需要知道算法内部细节


MarketModule

protocol MarketDataProvider {
    func fetchMarketList() async -> [MarketItem]
    func fetchStockDetail(stockId: String) async -> StockDetail
}

👉 好协议示例:

UI 只需要关心 MarketItem / StockDetail

✅ 后台是使用行情 SDK、还是换行情源,协议不变,UI 不受影响!


✅ 8️⃣ 总结一句话:

👉 协议 = 接口 → 定义要做什么,不定义怎么做

👉 好协议 = 暴露必要能力、意图清晰、隐藏实现细节、方便调用方用,方便实现方演进


🎁 9️⃣ 如何学习设计“更好的协议”?

✅ 多看优秀开源框架的 API 设计(Swift Standard LibraryAlamofireCombine

✅ 多总结自己项目里哪些协议“稳定 / 好用”,哪些协议“改动多 / 不好用”

✅ 在组件化阶段“协议先行” → 先画好“模块边界”图,再定义协议

✅ 协议定义时思考调用方“用起来是否舒服” → API 优雅很重要 🚀