Как использовать два метода десериализации с одинаковыми именами классов - PullRequest
0 голосов
/ 20 апреля 2020

В моем проекте я пытаюсь использовать десериализацию на основе Json и десериализацию на основе плоских буферов. Например, следующий Json из серверного API может быть десериализован в класс с именем ModelInfo, скажем, с использованием пакета freezed. Предположим, что этот класс определен в freezed_model.dart

{
 "model_name":"Model A",
 "model_size": 50
}

Теперь с того же самого бэкэнда я хочу отправить эту информацию как байтовый массив с использованием сериализации flatbuffer. С помощью flatc я могу сгенерировать код, который десериализует его в другой класс с таким же именем ModelInfo с идентичной информацией. Предположим, этот класс доступен в flatbuffer_model.dart

Я хотел бы использовать эти классы на уровне пользовательского интерфейса, менеджерах или API-уровнях в проекте флаттера, не конфликтуя с imports. Например, если мой виджет использует класс ModelInfo, я бы предпочел, чтобы он был динамически разрешен во время компиляции и во время выполнения из freezed_model.dart или flatbuffer_model.dart. Может быть, это невозможно, но я полагаю, что это не помешает.

Я пробовал условный импорт и условный экспорт, но анализатор дротиков это не устраивает, и я уверен, что мой подход неверен.

Например, я определил класс с именем environment.dart следующим образом.

import 'package:scandal_view/src/config_reader.dart';

enum Environment { PROD, DEV }

class CurrentEnvironment {
  static Environment _environment;
  /// assigning a default _decodeMode thinking dart analyser be able to resolve classes during 
  ///conditional export or import.
  static String _decodeMode = 'flatbuffers';

  static void initialize(Environment environment) {
    _environment = environment;
    // reassigns the _decomeMode during runTime.
    _decodeMode = ConfigReader.getDecodemode();
  }

  static Environment get environment => _environment;
  static String get decodeMode => _decodeMode;
}

После этого в своем классе API я попытался выполнить следующий условный импорт, но он не работает.

import 'dummy_model.dart' 
      if(CurrentEnvironment.decodeMode == 'json') 
            'package:mypackage/lib/model/json/freezed_model.dart'
      if(CurrentEnvironment.decodeMode == 'flatbuffer') 
            'package:mypackage/lib/model/flatbuffers/flatbuffer_model.dart'

На данный момент мой dummy_model.dart пуст. Ранее я использовал его для экспорта файлов, упомянутых выше, но это не помогло. Я подумываю использовать для этого паттерны фасадов, но это может привести к слишком большому количеству рукописного кода и склонности к ошибкам, поскольку десериализаторы генерируются автоматически и безопасны.

1 Ответ

1 голос
/ 20 апреля 2020

Если я не понял плохо, то, что вы пытаетесь достичь, это отделить ваш класс ModelInfo от выбранного вами подхода сериализации / десериализации (будь то json, плоские буферы и c), верно?

Если это так, то ваше предложение об условном импорте не будет работать (и, если это произойдет, я думаю, что это не будет хорошим вариантом, если речь идет о его обслуживании, тестировании или масштабировании.

My Было бы предложено следовать какому-либо шаблону репозитория самым простым из возможных способов. Это позволило бы вам действительно отделить способ получения ваших данных от потребителя, что позволило бы вам выбрать стратегию сериализации / десериализации или даже иметь несколько сериализаторов и т. д. c. Этот подход также очень упрощает добавление персистентности / кэша в ваше приложение в будущем, если вам это нужно.

Давайте представим простой сценарий, в котором вы хотите получить список объектов ModelInfo для использовать ваш бизнес-уровень (View Models, blocs et c), а затем ваш пользовательский интерфейс .

Давайте начнем с предположения, что у нас есть класс ModelInfo, который является целевым (тот, который мы хотим отправить на верхние уровни нашего приложения из уровня служб).

class ModelInfo {
    // This is the model we want to expose to our upper layers (View Models, Blocs etc) 
}

1) Сначала мы создадим интерфейс для определения контракта, который будет реализовывать каждый ApiDataManager. В Dart мы используем абстрактные классы для этого:

abstract class ApiDataManager {
  List<ModelInfo> fetchItems();
}

2 - Теперь мы можем создать столько менеджеров данных Api, сколько захотим (json, flatbuffers et c), если они соответствуют ApiDataManager. На этих менеджерах мы можем импортировать необходимые библиотеки и делать соответствующие вызовы API, parsing et c. Пока у нас есть метод fetchItems(), который возвращает List<ModelInfo>, у нас все в порядке.

class jsonApi implements ApiDataManager {

    List<ModelInfo> fetchItems() {
     /* Here you implement a fetchItem method that parses your json server response
     *  and returns an ItemModel list */
    }

}

class flatBuffersApi implements ApiDataManager {
     List<ModelInfo> fetchItems() {
     /* Here you implement a fetchItem method that parses your flatbuffers server response
      *  and returns an ItemModel list */
    }
}

3 - Теперь мы создадим репозиторий, в который мы добавим удаленного поставщика данных API, который вы хотите использовать ( json, плоские буферы). Этот репозиторий будет использоваться нашими моделями представления, Blocs et c, для извлечения данных и получения полностью законченных объектов модели.

class Repository {

  final ApiDataManager remoteDataManager;

  Repository(this.remoteDataManager);


  List<ModelInfo> fetchItems() {

    // Call remoteDataManager.fetchItems()
    // Depending on the remote data manager you have injected you'll be 
    // using json endpoints or flatbuffers, or whatever you want!
    // Return the list to your view models, Blocs etc

    return remoteDataManager.fetchItems();
  }

}

4 - И, наконец, мы можем использовать наш репозиторий из нашего бизнеса или слой представления (наш виджет) и получите наш список объектов ModelInfo. На самом деле мы можем динамически внедрить тип Api, который нам нужен во время выполнения, в зависимости от логики c, которую вы хотите использовать. Вы бы использовали логи c, как это в вашей ViewModel, blo c или Widget:

// Imagine this is inside your Widget or View Model or bloc

bool isProd = false; // Whatever you want to use to control the logic

var myJsonApi = JsonApi();
var myFlatBuffersApi = FlatBuffersApi();

var apiToUse = isProd ? JsonApi() : FlatBuffersApi();

Repository myRepository = Repository(apiToUse);

// Here you have your fresh list of items!
List<ModelInfo> myItems =  myRepository.fetchItems();

Надеюсь, это поможет!

...