2. 核心接口定义:IScanner、IConnector、IServiceManager 接口设计

在蓝牙扫描-连接-服务分离架构中,三个顶层接口承担着职责解耦的核心角色。IScanner 负责设备发现与广播监听,IConnector 负责建立/断开连接及连接参数管理,IServiceManager 负责服务发现、属性读写及通知订阅。三者彼此独立,仅通过统一的回调或异步事件总线通信,保证模块可单独替换测试。

2.1 接口职责与设计原则

接口核心职责设计原则
IScanner启动/停止扫描,过滤设备,回调发现结果无状态、可随时重新扫描;只暴露 BLE 状态无关的扫描参数
IConnector建立连接、断开连接、管理连接优先级与 MTU面向连接生命周期;通过连接句柄标识通道
IServiceManager发现服务/特征/描述符,读写属性,注册通知面向 GATT 层级;不依赖扫描状态

2.2 接口定义(C++ 类风格示例)

// IScanner.h
class IScanner {
public:
    virtual ~IScanner() = default;
    virtual void StartScan(const ScanFilter& filter, uint32_t timeout_ms) = 0;
    virtual void StopScan() = 0;
    // 结果通过回调传入
    using ScanResultCallback = std::function<void(const DeviceInfo& dev)>;
    virtual void SetScanResultCallback(ScanResultCallback cb) = 0;
};

// IConnector.h
class IConnector {
public:
    virtual ~IConnector() = default;
    virtual void Connect(const DeviceAddress& addr, uint16_t timeout_ms) = 0;
    virtual void Disconnect(const ConnectionHandle& handle) = 0;
    virtual void RequestConnectionPriority(const ConnectionHandle& handle, ConnectionPriority prio) = 0;
    // 连接状态回调
    using ConnectionStateCallback = std::function<void(const ConnectionHandle& handle, ConnectionState state)>;
    virtual void SetConnectionStateCallback(ConnectionStateCallback cb) = 0;
};

// IServiceManager.h
class IServiceManager {
public:
    virtual ~IServiceManager() = default;
    virtual void DiscoverServices(const ConnectionHandle& handle) = 0;
    virtual void ReadCharacteristic(const ConnectionHandle& handle, const AttributeHandle& attr) = 0;
    virtual void WriteCharacteristic(const ConnectionHandle& handle, const AttributeHandle& attr,
                                     const std::vector<uint8_t>& data, WriteType type) = 0;
    virtual void EnableNotification(const ConnectionHandle& handle, const AttributeHandle& attr,
                                    bool enable) = 0;
    // 数据及服务变更回调
    using ServiceDiscoveredCallback = std::function<void(const ConnectionHandle& handle,
                                        const ServiceList& services)>;
    using AttributeDataCallback = std::function<void(const ConnectionHandle& handle,
                                        const AttributeHandle& attr, const std::vector<uint8_t>& data)>;
    virtual void SetServiceDiscoveredCallback(ServiceDiscoveredCallback cb) = 0;
    virtual void SetAttributeDataCallback(AttributeDataCallback cb) = 0;
};

2.3 接口关系与注入流程

三个接口通过依赖注入(DI)组装到上层业务模块。业务层仅持有接口指针,不依赖具体实现。下图展示接口之间的协作关系与典型数据流:

接口依赖关系与数据流 IScanner 设备发现 IConnector 连接管理 IServiceManager GATT 服务 上层业务组件(注入接口) 回调事件总线(异步) 底层蓝牙硬件 / 系统栈 各接口通过回调事件总线向上层推送数据,业务层不直接耦合具体实现

2.4 实现流程与策略

  1. 定义接口纯抽象类(如上代码段),放入公共头文件目录。
  2. 为每个接口提供默认实现(如 Android 下的 AndroidScanner、AndroidConnector),同一接口可同时存在多个实现(模拟实现、基于不同蓝牙栈的实现)。
  3. 使用依赖注入容器(如手动工厂或轻量 DI 框架)在应用启动时组装:
    // 伪代码:工厂创建
    auto scanner = std::make_shared<AndroidScanner>();
    auto connector = std::make_shared<AndroidConnector>();
    auto serviceManager = std::make_shared<AndroidServiceManager>();
    auto app = std::make_shared<BluetoothApp>(scanner, connector, serviceManager);
  4. 业务层仅调用接口方法,不包含任何平台特定代码。
  5. 单元测试时注入 Mock 实现,以验证业务逻辑而不依赖硬件。

2.5 调试与验证

测试点方法预期行为
接口方法签名验证编译时检查所有派生类是否实现纯虚函数编译通过无 override 遗漏
回调注入正确性使用 MockScanner,StartScan 后立即调用回调业务层收到设备信息,状态机推进
连接状态转换MockConnector 模拟连接成功/超时/断开上层收到对应状态回调,不产生异常
服务发现与读写MockServiceManager 返回预设服务列表业务层正确解析 GATT 属性

2.6 常见错误与避坑

❌ 常见错误:在接口中暴露平台类型(如 android::sp<BluetoothDevice>),导致注入实现必须携带 Android 头文件。
✅ 正确做法:使用纯数据传输对象(如 DeviceAddress、ConnectionHandle)作为参数,与平台类型解耦。
💡 最佳实践:为每个接口提供一个空实现(Null Object Pattern),让业务层可以安全地在缺少某些功能时优雅降级,避免空指针检查污染代码。

2.7 性能与稳定性优化

  • 接口粒度控制:避免在 IServiceManager 中塞入连接断开功能,保持单一职责;过大的接口会导致实现类无法复用。
  • 异步设计:所有耗时操作(扫描、连接、服务发现)应通过回调异步返回,接口方法本身不应阻塞调用线程。
  • 连接句柄生命周期管理:ConnectionHandle 应在 IConnector 内部生成并回收,避免外部缓存失效。
  • 回调线程策略:在接口文档中明确回调执行线程(如 UI 线程 / 后台线程),实现类需遵守约定以避免死锁。
  • 内存控制:长连接场景下,IScanner 的扫描结果回调应支持批量化或节流,防止高频率回调导致业务层堆积。