简体   繁体   中英

How to call different class factory fromJson constructors via a variable in a parent (abstract) class method

I have an abstract class Listicle with a method, fetchItem() that includes

var item = Stock.fromJson(itemMap);

But I want to be able to use this method in various child classes, say in addition to StockListicle also in ClientListicle etc.

I imagined it should be possible to do something like pass a type parameter to the parent class' method, but how?

I've tried things like:

Future<Item> fetchItem(Type theType) async {
//...
Map<String, dynamic> itemMap = jsonDecode(response.body);
      var item = theType.fromJson(itemMap);
//...

But get the error

The method 'fromJson' isn't defined for the type 'Type' - maybe its just a syntax thing?

In my case Stock extends Item , and Stock has a fromJson factory constructor,

class Stock extends Item {
  final String thumbUrl;

  const Stock(
      {required super.id,
      required super.title,
      required super.description,
      required this.thumbUrl});

  @override
  List<Object> get props => [id, title, description, thumbUrl];

  factory Stock.fromJson(Map<String, dynamic> json) {
    developer.log('Stock.fromJson:');
    return Stock(
      id: json['id'],
      title: json['title'],
      description: json['description'],
      thumbUrl: json['thumbUrl'],
    );
  }
}

abstract class Item extends Equatable {
  const Item({
    required this.id,
    required this.title,
    required this.description,
  });

  final int id;
  final String title;
  final String description;

  @override
  List<Object> get props => [id, title, description];
}

I've also tried declaring an abstract method in the parent class containing the method in question to try and have that set by its child class, but no luck:

in the abstract class Listicle extends ChangeNotifier {...

Type getType();

in then in the the child class StockListicle extends Listicle {

@override
  Type getType() {
    return (Stock);
  }

Another throught was to connect the necessary functionality, so in the parent/base listicle `Function fromJsonFactory(json);' and then in the StockListicle something like

@override
  Function fromJsonFactory(json){
    return Stock.fromJson;
  }

and

var item =  fromJsonFactory(itemMap)  ;

but that gives

A value of type 'Function' can't be returned from the method 'fetchItem' because it has a return type of 'Future'.

Or is this 'counter-pattern' and I should just duplcate and amend the method between the child classes - it would seem awfully redundant though.

Thanks in advance.

I'm sure there must be a better way, however I got it working with an old-school switch:

Future<Item> fetchItem(Type theType) async {
//...
      switch (theType) {
        case Stock:
          return Stock.fromJson(itemMap);
        case Client:
          return Client.fromJson(itemMap);
        default:
          throw Exception("Didn't recognize $theType item type.");
      }

and in the child class I call

Stock tmpStock = await fetchItem(Stock) as Stock;

So, it seems the Type type is more like just a string version of the class name - though sure there must be something more elegant though at least this is quite readable ¯_(ツ)_/¯.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM