Files
social-app/docs/bugs/2026-03-27-repository缓存抽象.md
T

4.5 KiB

Repository 缓存层抽象优化

问题描述

现有架构

┌─────────────────────────────────────────┐
│           HybridCacheStore              │
│  (Memory + Persistent 二级缓存)         │
├─────────────────────────────────────────┤
│           CacheEntry<T>                 │
│  (value + fetchedAt 时间戳)             │
├─────────────────────────────────────────┤
│           CachePolicy                   │
│  (softTtl / hardTtl / minRefreshInterval)│
├─────────────────────────────────────────┤
│           CacheInvalidator              │
│  (统一失效管理)                         │
└─────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────┐
│         CalendarRepository              │  ← 重复实现
│         TodoRepository                  │  ← 重复实现
│         UsersRepository                 │  ← 重复实现
│         ...                             │
└─────────────────────────────────────────┘

重复内容

重复内容 例子
key 命名空间 calendar:day:$daytodo: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 基类

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. 各模块简化

// 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. 可选:泛型缓存装饰器

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 或优化逻辑只需改一处
易测试 基类可独立测试,子类继承即可

前置依赖

  • 现有 HybridCacheStoreCacheEntryCachePolicyCacheInvalidator 已就绪
  • 无需引入新依赖

状态

  • 待评估优先级
  • 待设计 CachedRepository 基类接口
  • 先在一个 Repository 上试点
  • 推广到其他 Repository