141 lines
4.5 KiB
Markdown
141 lines
4.5 KiB
Markdown
# Repository 缓存层抽象优化
|
|
|
|
## 问题描述
|
|
|
|
### 现有架构
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ HybridCacheStore │
|
|
│ (Memory + Persistent 二级缓存) │
|
|
├─────────────────────────────────────────┤
|
|
│ CacheEntry<T> │
|
|
│ (value + fetchedAt 时间戳) │
|
|
├─────────────────────────────────────────┤
|
|
│ CachePolicy │
|
|
│ (softTtl / hardTtl / minRefreshInterval)│
|
|
├─────────────────────────────────────────┤
|
|
│ CacheInvalidator │
|
|
│ (统一失效管理) │
|
|
└─────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────┐
|
|
│ CalendarRepository │ ← 重复实现
|
|
│ TodoRepository │ ← 重复实现
|
|
│ UsersRepository │ ← 重复实现
|
|
│ ... │
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
### 重复内容
|
|
|
|
| 重复内容 | 例子 |
|
|
|---------|------|
|
|
| key 命名空间 | `calendar:day:$day`、`todo:list:pending` |
|
|
| 缓存读取逻辑 | `store.read<CacheEntry<...>>(key)` |
|
|
| 数据转换 | API 返回 → CacheEntry 包装 |
|
|
| 刷新逻辑 | `_refreshDayAndRead()` |
|
|
| 强制刷新 | `forceRefresh` 参数处理 |
|
|
| 后台刷新防重 | `_refreshInFlight` map |
|
|
|
|
### 涉及文件
|
|
|
|
- `apps/lib/features/calendar/data/services/calendar_repository.dart`
|
|
- `apps/lib/features/todo/data/todo_repository.dart`
|
|
- `apps/lib/features/contacts/data/users/users_repository_impl.dart`
|
|
- `apps/lib/features/settings/data/services/user_profile_cache_repository.dart`
|
|
|
|
## 建议方案
|
|
|
|
### 1. 抽取 `CachedRepository` 基类
|
|
|
|
```dart
|
|
abstract class CachedRepository<T, R> {
|
|
HybridCacheStore get store;
|
|
CacheInvalidator get invalidator;
|
|
CachePolicy get policy;
|
|
|
|
String get namespace; // 'calendar', 'todo', etc.
|
|
|
|
Future<T> getOrLoad(
|
|
String key, {
|
|
bool forceRefresh = false,
|
|
required Future<R> Function() loader,
|
|
});
|
|
|
|
Future<void> invalidate(String key);
|
|
|
|
String buildKey(String suffix);
|
|
}
|
|
```
|
|
|
|
### 2. 各模块简化
|
|
|
|
```dart
|
|
// CalendarRepository
|
|
class CalendarRepository extends CachedRepository<List<ScheduleItemModel>, ScheduleItemModel> {
|
|
@override
|
|
String get namespace => 'calendar';
|
|
|
|
@override
|
|
Future<List<ScheduleItemModel>> getDayEvents(DateTime date, {bool forceRefresh}) {
|
|
return getOrLoad(
|
|
'day:${_formatDate(date)}',
|
|
forceRefresh: forceRefresh,
|
|
loader: () => calendarService.getEventsForDay(date),
|
|
);
|
|
}
|
|
|
|
String _formatDate(DateTime date) =>
|
|
'${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
|
|
}
|
|
|
|
// TodoRepository
|
|
class TodoRepository extends CachedRepository<List<TodoResponse>, TodoResponse> {
|
|
@override
|
|
String get namespace => 'todo';
|
|
|
|
Future<List<TodoResponse>> getPendingTodos({bool forceRefresh = false}) {
|
|
return getOrLoad(
|
|
'list:pending',
|
|
forceRefresh: forceRefresh,
|
|
loader: () => api.getPendingTodos(),
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. 可选:泛型缓存装饰器
|
|
|
|
```dart
|
|
class CachedApiCall<T> {
|
|
final HybridCacheStore store;
|
|
final CachePolicy policy;
|
|
final String key;
|
|
final DateTime Function() now;
|
|
|
|
Future<T> execute(Future<T> Function() loader);
|
|
}
|
|
```
|
|
|
|
## 收益
|
|
|
|
| 收益 | 说明 |
|
|
|------|------|
|
|
| 减少重复代码 | 各 Repository 移除 60%+ 相似逻辑 |
|
|
| 统一缓存行为 | 刷新策略、key 格式、并发控制一致 |
|
|
| 易维护 | 修复 bug 或优化逻辑只需改一处 |
|
|
| 易测试 | 基类可独立测试,子类继承即可 |
|
|
|
|
## 前置依赖
|
|
|
|
- 现有 `HybridCacheStore`、`CacheEntry`、`CachePolicy`、`CacheInvalidator` 已就绪
|
|
- 无需引入新依赖
|
|
|
|
## 状态
|
|
|
|
- [ ] 待评估优先级
|
|
- [ ] 待设计 CachedRepository 基类接口
|
|
- [ ] 先在一个 Repository 上试点
|
|
- [ ] 推广到其他 Repository
|