Flutter ~ Json序列化的抽象构造函数变通方法

r3i60tvu  于 2023-01-18  发布在  Flutter
关注(0)|答案(1)|浏览(105)

**背景:**我想创建一个抽象的JsonSerializable类,它允许它的扩展器拥有一个toJsonString-方法和一个fromJsonString构造函数,这样我就可以将对jsonDecodejsonEncode的所有调用捆绑在一个类中,同时还强制扩展器实现所需的toJson-metrhod和fromJson-构造函数。

到目前为止,我已经成功地做到了一半,就像这样:
json_serializable.dart

import 'dart:convert';

abstract class JsonSerializable {

  Map<String, dynamic> toJson();
  String toJsonString() => jsonEncode(toJson());
}

readable_uuid.dart

import 'dart:convert';

import 'package:uuid/uuid.dart';

import 'json_serializable.dart';

class ReadableUuid extends JsonSerializable {
  static const Uuid uuidGenerator = Uuid();
  String uuid = uuidGenerator.v4();

  static const String _uuidFieldName = "uuid";

  ReadableUuid();

  ReadableUuid.fromJson(Map<String, dynamic> json)
      : uuid = json[_uuidFieldName];

  ReadableUuid.fromJsonString(String jsonString)
      : this.fromJson(jsonDecode(jsonString));

  @override
  Map<String, dynamic> toJson() => {
        _uuidFieldName: uuid,
      };
  [...]
}

character_id.dart

import 'dart:convert';

import 'package:ceal_chronicler_f/utils/readable_uuid.dart';

import '../utils/json_serializable.dart';

class CharacterId extends JsonSerializable {
  static const String _idFieldName = "id";

  var id = ReadableUuid();

  CharacterId();

  CharacterId.fromJson(Map<String, dynamic> json)
      : id = ReadableUuid.fromJson(json[_idFieldName]);

  CharacterId.fromJsonString(String jsonString)
      : this.fromJson(jsonDecode(jsonString));

  @override
  Map<String, dynamic> toJson() => {
    _idFieldName: id,
  };
  [...]
}

这已经很不错了,但是这里仍然有一些重复。我的两个具体类仍然需要有一个实际上相同的fromJsonString构造函数,因此它们仍然需要导入dart:convert。而且,我不能强制它们有这样的fromJson构造函数。
现在,我想要的是这样的东西:
json_serializable.dart

import 'dart:convert';

abstract class JsonSerializable {

  abstract JsonSerializable.fromJson(Map<String, dynamic> json);
  JsonSerializable.fromJsonString(String jsonString)
      : this.fromJson(jsonDecode(jsonString));

  Map<String, dynamic> toJson();
  String toJsonString() => jsonEncode(toJson());
}

readable_uuid.dart

import 'package:uuid/uuid.dart';

import 'json_serializable.dart';

class ReadableUuid extends JsonSerializable {
  static const Uuid uuidGenerator = Uuid();
  String uuid = uuidGenerator.v4();

  static const String _uuidFieldName = "uuid";

  ReadableUuid();

  @override
  ReadableUuid.fromJson(Map<String, dynamic> json)
      : uuid = json[_uuidFieldName];

  @override
  Map<String, dynamic> toJson() => {
        _uuidFieldName: uuid,
      };
  [...]
}

character_id.dart

import 'package:ceal_chronicler_f/utils/readable_uuid.dart';

import '../utils/json_serializable.dart';

class CharacterId extends JsonSerializable {
  static const String _idFieldName = "id";

  var id = ReadableUuid();

  CharacterId();

  @override
  CharacterId.fromJson(Map<String, dynamic> json)
      : id = ReadableUuid.fromJson(json[_idFieldName]);

  @override
  Map<String, dynamic> toJson() => {
    _idFieldName: id,
  };
  [...]
}

现在,我知道这是行不通的,因为构造函数不是Dart中接口的一部分(Flutter不允许运行时反射,而支持树抖动,这使得它变得更加复杂)。我的问题是,有谁能想出一个变通方案来尽可能多地实现以下目标:

  • 具体类中无重复代码
  • dart:convert的所有依赖都集中在JsonSerializable
  • fromJson构造函数和toJson方法被强制存在于具体类中
myzjeezk

myzjeezk1#

我现在提出了一个“解决方案”,它解决了上述需求中的大约1.75个,但也有一些缺点。
首先,这里是“解决方案”:
json_serializable.dart

import 'dart:convert';

abstract class JsonSerializable {

  JsonSerializable();

  JsonSerializable.fromJsonString(String jsonString)
      : this.fromJson(jsonDecode(jsonString));

  JsonSerializable.fromJson(Map<String, dynamic> jsonMap){
    decodeJson(jsonMap);
  }

  decodeJson(Map<String, dynamic> jsonMap);

  Map<String, dynamic> toJson();

  String toJsonString() => jsonEncode(toJson());
}

readable_uuid.dart

import 'package:uuid/uuid.dart';

import 'json_serializable.dart';

class ReadableUuid extends JsonSerializable {
  static const Uuid uuidGenerator = Uuid();
  String uuid = uuidGenerator.v4();

  static const String _uuidFieldName = "uuid";

  ReadableUuid();

  ReadableUuid.fromJsonString(String jsonString)
      : super.fromJsonString(jsonString);

  ReadableUuid.fromJson(Map<String, dynamic> jsonMap) : super.fromJson(jsonMap);

  @override
  decodeJson(Map<String, dynamic> jsonMap) {
    uuid = jsonMap[_uuidFieldName];
  }

  @override
  Map<String, dynamic> toJson() => {
        _uuidFieldName: uuid,
      };
  [...]
}

character_id.dart

import 'package:ceal_chronicler_f/utils/readable_uuid.dart';

import '../utils/json_serializable.dart';

class CharacterId extends JsonSerializable {
  static const String _idFieldName = "id";

  var id = ReadableUuid();

  CharacterId();

  CharacterId.fromJsonString(String jsonString)
      : super.fromJsonString(jsonString);

  CharacterId.fromJson(Map<String, dynamic> jsonMap) : super.fromJson(jsonMap);

  @override
  decodeJson(Map<String, dynamic> jsonMap) {
    id = ReadableUuid.fromJson(jsonMap[_idFieldName]);
  }

  @override
  Map<String, dynamic> toJson() => {
        _idFieldName: id,
      };
  [...]
}

优点

  • 对dart:convert的所有依赖都集中在JsonSerializable中
  • JsonSerializable强制创建toJsondecodeJson方法
  • 小样本代码
    缺点
  • 仅当具体类的所有字段都使用默认值(late或nullable)初始化时才有效
  • 传送带构造函数每次都需要实现,尽管它们看起来总是一样的,这感觉有点重复

这将是我目前能想到的最好的解决方案。如果有人有更好的解决方案,请随时在这里分享。

相关问题