# 回调函数传递方案对比

## 📋 当前实现（方案1：反射调用 init 方法）

### 实现方式
```kotlin
// AppInitializer.kt
val initMethod = socketIOManagerClass.getDeclaredMethod(
    "init",
    Application::class.java,
    kotlin.jvm.functions.Function0::class.java,  // isLoggedInProvider
    kotlin.coroutines.SuspendFunction0::class.java   // refreshTokenProvider
)
initMethod.invoke(null, application, isLoggedInProvider, refreshTokenProvider)
```

### 优点 ✅
1. **初始化逻辑集中**：init 方法同时完成生命周期注册和回调设置
2. **原子性操作**：一次调用完成所有初始化，不会出现部分初始化状态
3. **符合单例模式**：标准的单例初始化模式
4. **类型安全**：回调函数在编译时创建，类型明确

### 缺点 ❌
1. **反射调用复杂**：需要处理 `SuspendFunction0` 类型，反射代码复杂
2. **可读性差**：反射代码不够直观
3. **错误处理复杂**：反射异常处理需要更多代码

---

## 🔄 方案2：分步设置（先 init，再设置属性）

### 实现方式
```kotlin
// SocketIOManager.kt
fun init(app: Application) {
    // 只负责注册生命周期监听
    ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}

// AppInitializer.kt
// 1. 先调用 init（注册生命周期）
val initMethod = socketIOManagerClass.getMethod("init", Application::class.java)
initMethod.invoke(null, application)

// 2. 再设置回调属性（直接设置，不需要处理 suspend 函数类型）
val isLoggedInProviderField = socketIOManagerClass.getDeclaredField("isLoggedInProvider")
isLoggedInProviderField.isAccessible = true
isLoggedInProviderField.set(null, isLoggedInProvider)

val refreshTokenProviderField = socketIOManagerClass.getDeclaredField("refreshTokenProvider")
refreshTokenProviderField.isAccessible = true
refreshTokenProviderField.set(null, refreshTokenProvider)
```

### 优点 ✅
1. **反射代码简单**：设置属性比调用方法更简单
2. **不需要处理 suspend 函数类型**：直接设置属性，反射不需要知道 suspend 类型
3. **灵活性高**：可以随时修改回调函数
4. **可读性好**：分步操作，逻辑清晰

### 缺点 ❌
1. **初始化逻辑分散**：需要两步操作
2. **可能出现部分初始化**：如果第二步失败，可能出现只注册了生命周期但没设置回调的情况
3. **需要访问私有字段**：需要 `setAccessible(true)`，可能违反封装原则
4. **错误处理分散**：需要分别处理 init 和属性设置的异常

---

## 📊 客观对比

| 维度 | 方案1：反射调用 init | 方案2：分步设置属性 |
|------|---------------------|-------------------|
| **代码复杂度** | ⭐⭐⭐ 复杂（需要处理 SuspendFunction0） | ⭐⭐ 简单（直接设置属性） |
| **可读性** | ⭐⭐ 一般（反射代码不够直观） | ⭐⭐⭐ 好（分步操作清晰） |
| **类型安全** | ⭐⭐⭐ 好（编译时类型检查） | ⭐⭐ 一般（运行时设置） |
| **原子性** | ⭐⭐⭐ 好（一次调用完成） | ⭐⭐ 一般（分步操作） |
| **错误处理** | ⭐⭐ 一般（集中处理） | ⭐⭐ 一般（分散处理） |
| **灵活性** | ⭐⭐ 一般（需要重新 init） | ⭐⭐⭐ 好（可随时修改） |
| **封装性** | ⭐⭐⭐ 好（通过方法调用） | ⭐⭐ 一般（直接访问字段） |

---

## 🎯 推荐方案

### 推荐：**方案2（分步设置）**

**理由：**
1. ✅ **反射代码更简单**：设置属性比调用方法简单，不需要处理复杂的 suspend 函数类型
2. ✅ **可读性更好**：分步操作逻辑清晰，易于理解和维护
3. ✅ **实际风险低**：虽然可能出现部分初始化，但在 AppInitializer 中集中处理，风险可控
4. ✅ **符合常见模式**：很多框架都是先初始化，再配置回调

**改进建议：**
- 在 SocketIOManager 中添加 `setCallbacks()` 方法，通过方法设置而不是直接访问字段
- 这样可以保持封装性，同时简化反射代码

---

## 💡 改进方案（推荐）

### 方案3：添加 setCallbacks 方法（最佳）

```kotlin
// SocketIOManager.kt
fun init(app: Application) {
    // 只负责注册生命周期监听
    ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}

fun setCallbacks(
    isLoggedInProvider: (() -> Boolean)? = null,
    refreshTokenProvider: (suspend () -> String?)? = null
) {
    this.isLoggedInProvider = isLoggedInProvider
    this.refreshTokenProvider = refreshTokenProvider
}

// AppInitializer.kt
// 1. 先调用 init（注册生命周期）
val initMethod = socketIOManagerClass.getMethod("init", Application::class.java)
initMethod.invoke(null, application)

// 2. 再调用 setCallbacks（设置回调）
val setCallbacksMethod = socketIOManagerClass.getMethod(
    "setCallbacks",
    kotlin.jvm.functions.Function0::class.java,  // isLoggedInProvider
    kotlin.coroutines.SuspendFunction0::class.java   // refreshTokenProvider
)
setCallbacksMethod.invoke(null, isLoggedInProvider, refreshTokenProvider)
```

**优势：**
- ✅ 保持封装性（通过方法而不是字段）
- ✅ 反射代码相对简单（调用方法比设置字段更标准）
- ✅ 逻辑清晰（分步操作）
- ✅ 类型安全（方法签名明确）

**缺点：**
- ⚠️ 仍然需要处理 `SuspendFunction0` 类型（但比方案1简单，因为方法签名更清晰）

---

## 📝 结论

**当前方案（方案1）的问题：**
- 反射调用 init 方法时，需要处理复杂的 `SuspendFunction0` 类型
- 虽然功能正常，但代码复杂度较高

**推荐改进：**
- 采用**方案3（添加 setCallbacks 方法）**
- 或者采用**方案2（分步设置属性）**（如果不在意直接访问字段）

**最终建议：**
- 如果追求代码简洁：使用**方案2（分步设置属性）**
- 如果追求封装性：使用**方案3（添加 setCallbacks 方法）**

