首页 > 解决方案 > Flutter 从服务返回解析动态对象

问题描述

我创建了多个模型并使用 json_serialization

示例公司和员工等等。

import 'package:json_annotation/json_annotation.dart';

part 'company.g.dart';

@JsonSerializable()
class Company {
  Company({this.id, this.name});

  String id;
  String name;


  factory Company.fromJson(Map<String, dynamic> json) => _$CompanyFromJson(json);

  Map<String, dynamic> toJson() => _$CompanyToJson(this);
}
import 'package:json_annotation/json_annotation.dart';

part 'employee.g.dart';

@JsonSerializable()
class Employee {
  Employee({this.id, this.name, this.email, this.phone, this.photo});

  String id;
  String name;
  String email;
  String phone;
  String photo;

  factory Employee.fromJson(Map<String, dynamic> json) => _$EmployeeFromJson(json);

  Map<String, dynamic> toJson() => _$EmployeeToJson(this);
}

现在我想创建一个可重用的服务,它可以返回带有 Company、Employee 或其他类型的 Stream。我正在使用 Firebase,所以返回类型是 Map。

示例服务类

class BaseService<T> {
  final String collection;
  CollectionReference _collectionRef;

  FirebaseBase({@required this.collection}) {
    _collectionRef = Firestore.instance.collection(collection);
  }

  Stream<List<T>> find() {
    return inColRef.snapshots().map((list) {
      return list.documents.map((doc) {
        final Map<String, dynamic> data = doc.data;
        data['id'] = doc.documentID;
        return data;
      }).toList();
    });
  }
}

如何将返回数据(地图)转换为 Company 或 Employee 类型。

这些类可以使用 fromJson(data) 的工厂。但我不能返回 T.fromJson(data)。

我想得到

Stream<List<Company>> companies = ServiceBase('companies').find();
Stream<List<Employee>> employees = ServiceBase('employee').find();

标签: flutterdart

解决方案


这是您使用当前代码完成通用分配的方式:

class BaseService<T> {
  final String collection;
  CollectionReference _collectionRef;

  FirebaseBase({@required this.collection}) {
    _collectionRef = Firestore.instance.collection(collection);
  }

  Stream<List<T>> find() {
    return inColRef.snapshots().map((list) {
      return list.documents.map((doc) {
        final Map<String, dynamic> data = doc.data;
        data['id'] = doc.documentID;
        return _build(data) as T;
      }).toList();
    });
  }

  dynamic _build(final Map<String, dynamic> data) {
      if(collection == 'companies') {
         return Company.fromJson(data);
      } else if(collection == 'employee') {
         return Employee.fromJson(data);
      }
      ... throw if invalid collection passed ? ... 
  }
}

这将被称为:

Stream<List<Company>> companies = BaseService<Company>('companies').find();
Stream<List<Employee>> employees = BaseService<Employee>('employee').find();

我建议您使用模板方法模式使用不同的对象结构,例如:

class CompanyService extends BaseService<Company> {
      CompanyService() : super('companies');

      Company build(final Map<String, dynamic> data) => Company.fromJson(data);   
}
class EmployeeService extends BaseService<Employee> {
      EmployeeService() : super('employee');

      Employee build(final Map<String, dynamic> data) => Employee.fromJson(data);   
}
abstract class BaseService<T> {
      final String collection;
      CollectionReference _collectionRef;
      BaseService(this.collection) {
         _collectionRef = Firestore.instance.collection(collection);
      }

      T build(final Map<String, dynamic> data);

      Stream<List<T>> find() {
        return inColRef.snapshots().map((list) {
           return list.documents.map((doc) {
           final Map<String, dynamic> data = doc.data;
           data['id'] = doc.documentID;
           return build(data);
        }).toList();
    });
      }
}

这将导致调用代码看起来像这样:

Stream<List<Company>> companies = CompanyService().find();
Stream<List<Employee>> employees = EmployeeService().find();

推荐阅读