Общие ограничения в Dart

#json #http #dart #model

#json #http #dart #Модель

Вопрос:

Мне нужно абстрагировать мою систему синтаксического анализа модели в 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);
   }
}
  

мой класс базовой модели таков:

 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);
   }
  

Ответ №1:

К сожалению, T.fromJson() это невозможно. Обходным путем является поддержка фабрик для создания экземпляров.

Некоторые предостережения:

  1. Вы не можете отключить именованные конструкторы.
  2. Статические функции не наследуются, и нет способа требовать от подклассов их реализации.
  3. Наличие нестатической виртуальной функции from или create усложняет неизменяемые классы и код, не обнуляемый по умолчанию.
  4. Каждый применимый подкласс должен как реализовывать шаблон create или from, так и добавляться в factory map .

В целом, я думаю, было бы лучше передать полученный 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);
}