You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart无静态接口场景下HTTP请求对象缓存构造方案咨询

方案1:显式传入工厂构造器(零反射、类型安全)

Dart不支持静态方法继承,最直接的解决方案是把对应类型的HTTP请求方法作为参数传入CachedFuture,完全规避静态接口的限制。
首先定义通用的请求方法类型:

typedef HttpGetter<T> = Future<T?> Function(int id);

改造后的CachedFuture实现:

class CachedFuture<T> {
  final int _id;
  final HttpGetter<T> _httpGetter;
  Future<T?>? _cachedResult;

  CachedFuture({required int id, required HttpGetter<T> httpGetter})
      : _id = id,
        _httpGetter = httpGetter;

  Future<T?> get() {
    // 只有首次调用会发起请求,后续直接返回缓存结果
    _cachedResult ??= _httpGetter(_id).onError((error, stackTrace) => null);
    return _cachedResult!;
  }
}

使用示例:

class User {
  final int id;
  final String name;

  User({required this.id, required this.name});

  // 对应实体类自己实现静态请求方法
  static Future<User?> httpGet(int id) async {
    // 实际的HTTP请求、解析逻辑
    final response = await http.get(Uri.parse('/users/$id'));
    if (response.statusCode == 200) {
      final json = jsonDecode(response.body);
      return User(id: json['id'], name: json['name']);
    }
    return null;
  }
}

// 构造引用
final userRef = CachedFuture<User>(id: 123, httpGetter: User.httpGet);
// 首次调用发起请求,后续调用直接返回缓存
final user = await userRef.get();

方案2:全局工厂注册表(简化调用侧代码)

如果觉得每次传httpGetter太繁琐,可以统一维护一个全局的类型-请求方法映射表,只需要在应用启动时完成一次注册即可:

// 全局注册表
final _httpGetterRegistry = <Type, HttpGetter>{};

// 注册方法
void registerHttpGetter<T>(HttpGetter<T> getter) {
  _httpGetterRegistry[T] = getter;
}

// 改造后的CachedFuture,无需传入请求方法
class CachedFuture<T> {
  final int _id;
  Future<T?>? _cachedResult;

  CachedFuture({required int id}) : _id = id {
    // 运行时检查是否漏注册,提前暴露问题
    if (!_httpGetterRegistry.containsKey(T)) {
      throw StateError('No HttpGetter registered for type $T');
    }
  }

  Future<T?> get() {
    final getter = _httpGetterRegistry[T] as HttpGetter<T>;
    _cachedResult ??= getter(_id).onError((error, stackTrace) => null);
    return _cachedResult!;
  }
}

使用示例:

// 应用启动时统一注册所有实体类的请求方法
void main() {
  registerHttpGetter<User>(User.httpGet);
  registerHttpGetter<Post>(Post.httpGet);
  runApp(const MyApp());
}

// 构造引用时代码更简洁,和你最初的设计预期一致
final userRef = CachedFuture<User>(id: 123);
final user = await userRef.get();

两种方案都完全不需要依赖反射,避免了反射带来的类型不安全、打包后tree shaking导致的异常问题,性能损耗几乎为零,也完全满足你需要的缓存透明、请求逻辑封装的需求。

内容的提问来源于stack exchange,提问作者CBlumey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 02:27:00