I want to declare, but not define a factory constructor in an abstract class.
In my case, I want to create a method that accepts any class that implements a St
As suggested in the accepted answer, I ended up creating a Serializer<T>
type that got implemented by a serializer for each class:
Turns out, this has several benefits over just having toJson
/fromJson
on the classes directly:
String
or Flutter's Color
, where you can't just add a fromColor
constructor.Code example:
class Fruit {
Fruit(this.name, this.color);
final String name;
final String color;
}
// in another file
class FruitSerializer extends Serializer<Fruit> {
Map<String, dynamic> toJson(Fruit fruit) {
return ...;
}
Fruit fromJson(Map<String, dynamic> data) {
return Fruit(...);
}
}
An then also pass the serializer to the code that needs it:
someMethod<T>(Serializer<T> serializer, T value) {
...
}
someMethod(FruitSerializer(), someFruit);
final fruit = recreateFruit(FruitSerializer());
Obviously, you can't pass an object that can't be serialized to the code, because the method expects a Serializer<T>
.
I'm afraid that it doesn't work the way you want it to.
Constructors are not part of an interface. They act more like static members. So, you can't add a factory to the interface, and code wouldn't have any way to call the factory constructor given a type variable extending this type anyway.
So, since constructors cannot be part of interfaces, constructors also cannot be abstract. Being abstract simply means "make the member part of the interface, but no implementation is added to class".
You can declare the factory as a normal method, but then you would only be able to call it when you already have an instance, which likely isn't what you want with a constructor.
The only way to pass code around is as functions or objects with methods. So, if you want to parameterize something by a type which is JsonSerializable
, and you want to be able to create such an object, you need to pass a factory function along:
T deserialize<T extends JsonSerializable>(
String json,
T factory(Map<String, dynamic> data),
) {
return factory(jsonDecode(json) as Map<String, dynamic>);
}
You an then call it with:
var myValue = deserialize(jsonString, (x) => MyClass.fromJson(x));
(If MyClass.fromJson
had been a static function instead of a constructor, you could just write deserialize(jsonString, MyClass.fromJson)
, but Dart doesn't yet have constructor tear-offs).