我需要在http请求中抽象我的模型解析系统
我有一个HttpClient类

class HttpClient {
   Dio dio = new Dio();

   Future<T> get<T extends BaseModel>(String url) {
      Response response = await dio.get(url);
      T.fromJson(response.body);
   }
}
我的BaseModel类是这样的:
abstract class BaseModel {
 fromJson(Map<String, dynamic> json);
 toJson();
}
和一个模型的例子:
class Person extends BaseModel {
  String name;
  String surname;
  int age;

  Person({this.name, this.surname, this.age});

  Person.fromJson(Map<String, dynamic> json) {
    // parse ToModel;
  }

  Map<String, dynamic> toJson() {
    // parse toJson;
  }
}
我想像这样消耗我的HttpClient:
class RandomClassToConsumeHttp {

   HttpClient _httpClient;
   Person person;

   RandomClassToConsumeHttp(this._httpClient);


   void _getPerson() async {
     _person = await _httpClient.get<Person>("api/getPerson");
   }
}
问题是:
我的get方法中有一个泛型,并且我需要泛型来扩展BaseModel类,因此我将始终具有fromJson()的实现,并根据发送给该泛型的模型类型进行模型解析
我不知道是否有可能在dart中执行这样的常规约束,并且我需要使用该类型的fromJson,有人知道它是否可能吗?或者还有其他解决方案
   Future<T> get<T extends BaseModel>(String url) {
      Response response = await dio.get(url);
      T.fromJson(response.body);
   }

最佳答案

不幸的是,T.fromJson()是不可能的。解决方法是维护工厂以创建实例。
一些警告:

  • 您不能删除命名的构造函数。
  • 静态函数不会被继承,也无法要求子类实现它们。
  • 具有from或create函数的非静态虚函数会使不变的类和非null的默认代码变得复杂。
  • 每个适用的子类都需要实现create或from模式,并添加到工厂映射中。

  • 总而言之,我认为最好将接收到的json传递给模型的构造函数,例如:
    var model = SomeModel.fromJson(httpClient.get('resource'));
    
    最后,这是一个工厂实现示例:
    abstract class Base {
      static from(v) => SubA.from(v);
    }
    
    class SubA extends Base {
      static from(v) => SubA();
    }
    
    class SubB extends Base {
      static from(v) => SubB();
    }
    
    final _baseFromFactory = {
      Base: Base.from,
      SubA: SubA.from,
      SubB: SubB.from,
      // or you can do:
      // SubB: (v) => /* create instance */
    };
    
    class Client {
      get<T extends Base>(v) => _baseFromFactory[T](v);
    
      // Alternatively, you can switch on T.
      getAlt<T extends Base>(v) {
        switch (T) {
          case SubB: return SubB.from(v);
          default: return SubA.from(v);
        }
      }
    }
    
    main() {
      var client = Client();
      var subA = client.get<SubA>('a value');
      var subB = client.get<SubB>('a value');
      var altA = client.getAlt<SubA>('a value');
      var altB = client.getAlt<SubB>('a value');
    
      print(subA);
      print(subB);
      print(altA);
      print(altB);
    }
    

    09-11 13:49