第3章 依赖注入集成BLE的设计模式:桥接模式、工厂模式、单例管理

3.1 三种模式在BLE集成中的定位

在依赖注入框架中集成BLE组件,需要解决三个核心问题:抽象与实现的解耦、复杂对象的统一创建、全局资源的生命周期管控。桥接模式、工厂模式与单例管理分别对应上述三个问题,形成一套可复用的架构方案。

设计模式核心作用在BLE集成中的职责
桥接模式(Bridge)将抽象部分与实现部分分离分离BLE操作接口(扫描、连接、收发)与底层平台实现(Android/iOS)
工厂模式(Factory)封装对象创建逻辑统一创建BLE适配器、设备代理、服务特征对象,避免直接new依赖
单例管理(Singleton)确保全局唯一实例管理BLE中央管理器、应用上下文、连接池等共享资源
架构提示:三种模式并非孤立使用,而是通过依赖注入容器组合为有机整体。单例提供全局状态,工厂封装创建细节,桥接保证平台可移植性。
依赖注入集成BLE — 三种设计模式协作架构图 Singleton 单例管理层 BLEManager + AppContext + 连接池 Factory 工厂模式 BLEAdapterFactory BLEProxyFactory · ServiceFactory Bridge 桥接模式 IBLEAdapter(抽象接口) AndroidAdapter · iOSAdapter DI Container 依赖注入容器 Hilt / Dagger / Koin 管理所有依赖 提供全局上下文 注入平台依赖 注册工厂实例 注入抽象实现 工厂创建桥接实现 三种模式协作说明 单例管理全局资源 → 工厂负责创建具体组件 → 桥接隔离平台差异 → DI容器统一装配

3.2 桥接模式:抽象与实现的分离

3.2.1 原理

桥接模式将BLE操作接口(扫描、连接、发现服务、收发数据)定义为抽象层,而具体实现委托给平台适配器。抽象层与实现层通过组合关系连接,两者可以独立演化。

3.2.2 接口定义

// 抽象接口:BLE 适配器
protocol IBLEAdapter {
    fun startScan(timeout: Long): Flow<ScanResult>
    fun connect(deviceId: String): Flow<ConnectionState>
    fun discoverServices(deviceId: String): Flow<List<BLEService>>
    fun writeCharacteristic(deviceId: String, service: String, char: String, data: ByteArray): Flow<WriteResult>
    fun readCharacteristic(deviceId: String, service: String, char: String): Flow<ByteArray>
    fun setNotification(deviceId: String, service: String, char: String, enable: Boolean): Flow<NotificationData>
    fun disconnect(deviceId: String)
    fun release()
}

3.2.3 实现示例

// Android 平台实现
class AndroidBLEAdapter @Inject constructor(
    private val context: Context
) : IBLEAdapter {
    private val bluetoothManager: BluetoothManager by lazy {
        context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    }
    private val bluetoothAdapter: BluetoothAdapter by lazy {
        bluetoothManager.adapter
    }

    override fun startScan(timeout: Long): Flow<ScanResult> = callbackFlow {
        val scanner = bluetoothAdapter.bluetoothLeScanner
            ?: throw IllegalStateException("Bluetooth LE not supported")
        // ... 扫描逻辑实现
    }

    override fun release() {
        // 释放 Android 平台资源
    }
}

// iOS 平台实现
class iOSBLEAdapter @Inject constructor(
    private val centralManager: CBCentralManager
) : IBLEAdapter {
    override fun startScan(timeout: Long): Flow<ScanResult> = callbackFlow {
        // ... iOS CoreBluetooth 扫描实现
    }

    override fun release() {
        // 释放 iOS 平台资源
    }
}
桥接优势:当新增平台(如HarmonyOS、Windows)时,只需新增一个实现类,抽象接口和上层业务代码完全不受影响。依赖注入容器负责将正确的平台实现注入到消费者中。

3.3 工厂模式:统一对象创建

3.3.1 原理

BLE组件体系中存在大量复杂对象(适配器、代理、服务特征包装器),直接使用构造函数创建会导致依赖混乱。工厂模式集中管理这些对象的创建逻辑,并配合DI框架提供注入所需的实例。

3.3.2 工厂接口与实现

// 工厂抽象
interface BLEAdapterFactory {
    fun createAdapter(): IBLEAdapter
    fun createDeviceProxy(deviceId: String): BLEDeviceProxy
    fun createServiceWrapper(service: BLEService): ServiceWrapper
}

// Android 平台工厂
class AndroidBLEAdapterFactory @Inject constructor(
    private val context: Context
) : BLEAdapterFactory {
    override fun createAdapter(): IBLEAdapter {
        return AndroidBLEAdapter(context)
    }

    override fun createDeviceProxy(deviceId: String): BLEDeviceProxy {
        val adapter = createAdapter()
        return BLEDeviceProxy(adapter, deviceId)
    }

    override fun createServiceWrapper(service: BLEService): ServiceWrapper {
        return ServiceWrapper(service)
    }
}

// iOS 平台工厂
class iOSBLEAdapterFactory @Inject constructor(
    private val centralManager: CBCentralManager
) : BLEAdapterFactory {
    override fun createAdapter(): IBLEAdapter {
        return iOSBLEAdapter(centralManager)
    }

    override fun createDeviceProxy(deviceId: String): BLEDeviceProxy {
        val adapter = createAdapter()
        return BLEDeviceProxy(adapter, deviceId)
    }

    override fun createServiceWrapper(service: BLEService): ServiceWrapper {
        return ServiceWrapper(service)
    }
}

3.3.3 在DI模块中注册工厂

// Hilt 模块示例
@Module
@InstallIn(SingletonComponent::class)
object BLEFactoryModule {

    @Provides
    @Singleton
    fun provideAdapterFactory(context: Context): BLEAdapterFactory {
        return if (Platform.isAndroid()) {
            AndroidBLEAdapterFactory(context)
        } else {
            // 通过依赖注入获取 iOS 的 CBCentralManager
            iOSBLEAdapterFactory(provideCentralManager())
        }
    }

    @Provides
    fun provideAdapter(factory: BLEAdapterFactory): IBLEAdapter {
        return factory.createAdapter()
    }
}
工厂模式陷阱:避免在工厂内部持有长时间存活的状态(如缓存列表),否则会导致单例与工厂职责混淆。工厂只负责“创建”,不负责“管理生命周期”。生命周期管理应交给单例或DI容器。

3.4 单例管理:全局资源管控

3.4.1 原理

BLE系统中存在多个必须全局唯一的资源:蓝牙中央管理器(CBCentralManager / BluetoothAdapter)、应用上下文、已连接设备池、扫描回调注册表等。单例模式确保这些资源不会重复创建,避免状态冲突。

3.4.2 BLEManager单例设计

@Singleton
class BLEManager @Inject constructor(
    private val adapterFactory: BLEAdapterFactory,
    private val adapter: IBLEAdapter
) {
    // 设备连接池:全局唯一
    private val devicePool = ConcurrentHashMap<String, BLEDeviceProxy>()

    // 扫描状态
    private val _scanState = MutableStateFlow<ScanState>(ScanState.Idle)
    val scanState: StateFlow<ScanState> get() = _scanState.asStateFlow()

    // 连接状态聚合
    private val _connectionStates = MutableStateFlow<Map<String, ConnectionState>>(emptyMap())
    val connectionStates: StateFlow<Map<String, ConnectionState>> get() = _connectionStates.asStateFlow()

    fun startScan(timeout: Long = 10_000) {
        if (_scanState.value is ScanState.Scanning) return
        _scanState.value = ScanState.Scanning
        adapter.startScan(timeout)
            .onEach { result ->
                // 处理扫描结果
            }
            .catch { error ->
                _scanState.value = ScanState.Error(error.message ?: "Unknown error")
            }
            .launchIn(CoroutineScope(Dispatchers.IO))
    }

    suspend fun connect(deviceId: String): ConnectionState {
        return adapter.connect(deviceId)
            .map { state ->
                if (state is ConnectionState.Connected) {
                    devicePool[deviceId] = adapterFactory.createDeviceProxy(deviceId)
                }
                state
            }
            .first()
    }

    fun getDeviceProxy(deviceId: String): BLEDeviceProxy? {
        return devicePool[deviceId]
    }

    fun release() {
        devicePool.values.forEach { it.disconnect() }
        devicePool.clear()
        adapter.release()
    }
}

3.4.3 单例的依赖注入注册

// Hilt 单例绑定
@Module
@InstallIn(SingletonComponent::class)
object BLEManagerModule {

    @Provides
    @Singleton
    fun provideBLECentralManager(context: Context): CBCentralManager {
        // 仅iOS需要,Android通过context获取
        return CBCentralManager(context, null, null)
    }

    @Provides
    @Singleton
    fun provideBLEManager(
        adapterFactory: BLEAdapterFactory,
        adapter: IBLEAdapter
    ): BLEManager {
        return BLEManager(adapterFactory, adapter)
    }
}
单例边界:BLEManager 单例应仅管理跨组件共享的状态(连接池、扫描状态),具体的业务数据(设备名称、服务列表)应通过数据层单独管理,避免单例膨胀为“上帝对象”。

3.5 三种模式的协作流程

在依赖注入框架下,三种模式按以下流程协同工作:

  1. DI容器启动 → 通过 @Singleton 创建 BLEManager 实例(单例管理)。
  2. 消费方请求依赖 → DI容器查找 BLEAdapterFactory 工厂实例(工厂模式)。
  3. 工厂创建适配器 → 根据平台类型创建 AndroidBLEAdapter 或 iOSBLEAdapter(桥接模式)。
  4. 适配器注入消费者 → ViewModel/Service 通过构造函数接收 IBLEAdapter 抽象,调用扫描、连接等方法。
  5. 单例协调全局状态 → BLEManager 统一管理连接池和扫描状态,避免多个消费者之间的资源冲突。

3.6 常见错误与优化

错误/问题原因解决方案
工厂内缓存对象导致内存泄漏工厂持有已创建的组件引用,阻止GC回收工厂只负责创建,不维护缓存;缓存由单例管理
桥接接口粒度过粗单个接口包含扫描+连接+数据收发,导致平台实现耦合按职责拆分接口:IScanner、IConnector、IDataChannel
单例持有Activity Context单例长生命周期持有短生命周期的Context使用Application Context注入,避免内存泄漏
多个单例相互循环依赖BLEManager依赖Factory,Factory依赖Manager引入中间接口或通过DI容器延迟注入(Lazy)
平台条件判断分散多处使用 if(platform) 判断Android/iOS统一在工厂模块内做平台分发,其余代码面向接口编程

3.7 性能与稳定性建议

  • 桥接层使用协程Flow:所有BLE操作返回 Flow<T>,方便上层做响应式组合和生命周期取消,避免回调嵌套。
  • 工厂实例池化:对于频繁创建的轻量对象(如ServiceWrapper),工厂可配合对象池复用,减少GC压力。
  • 单例状态线程安全:使用 ConcurrentHashMap、Mutex 或 StateFlow 保证多线程环境下的状态一致性。
  • DI作用域收敛:BLE相关的单例统一放在 @Singleton 作用域,避免跨作用域导致的重复实例。
  • 平台适配器懒加载:在首次需要执行BLE操作时才初始化平台适配器,避免冷启动时加载不必要的蓝牙服务。
架构总结:桥接模式提供了平台无关的抽象层,工厂模式封装了复杂对象的创建过程,单例管理保证了全局资源的唯一性与一致性。三者通过依赖注入容器无缝集成,形成一套高内聚、低耦合的BLE组件架构,可稳定支撑多平台蓝牙开发需求。