Dart standardizing logic of child class clone methods using existing Map methods

78 views Asked by At

I am trying to standardize the logic of a class.clone method so that every child of my abstract class clones the exact same way.

I've tried using factory constructors and all sorts of roundabouts but I can't seem to find a solution that doesn't require adding an additional function specifically for cloning, which I feel is redundant and opens me up to unwanted variance in how cloning works down the line.

The class structure is as follows:

abstract class ParentClass<T extends ParentClass<T>> {
  String foo;
  int bar;

  Model({
    String? foo,
    int? bar
    Map? kwargs,
  })  : foo = foo ?? kwargs?['foo'] ?? "Not provided",
        bar = bar ?? kwargs?['bar'] ?? 0;

  Map<String, dynamic> toMap();
  // toMap always returns approximately {'foo':foo1, 'bar':bar1, "x":x1, etc.}

  T clone();
  //Optimally along the lines of T clone() => T(kwargs:toMap())
}
1

There are 1 answers

0
Jimmy Donovan On BEST ANSWER

Thanks ApaxPhoenix for pointing me in the right direction.

The copy pattern seems like a good practice generally but in my case there are properties of the child class which also need to be cloned by the same method. What I ended up doing is changing every child class to pass its own default constructor to itself since I know they all must follow the same system of x = x ?? kwargs['x'] for every relevant property

typedef ModelFactory<T> = T Function({Map<String, dynamic>? kwargs});

abstract class ParentClass<T extends ParentClass<T>> {
  String foo;
  int bar;
  final ModelFactory<T> tType;

  Model({
    String? foo,
    int? bar
    Map? kwargs,
    required this.tType, // As ModelFactory<T> in child constructor
  })  : foo = foo ?? kwargs?['foo'] ?? "Not provided",
        bar = bar ?? kwargs?['bar'] ?? 0;

  Map<String, dynamic> toMap();
  // toMap always returns approximately {'foo':foo1, 'bar':bar1, "x":x1, etc.}

  T clone() => tType(kwargs: toMap()); //new clone
}

class childClass extends ParentClass<childClass> {
    double x; // New child-specific property
    childClass({
        String? foo,
        int? bar
        Map? kwargs,
        double? x,
      })  : x = x ?? kwargs['x'] ?? 0.0,
       super(foo: foo ?? kwargs?['foo'] ?? "Not provided",
            bar: bar ?? kwargs?['bar'] ?? 0
            tType: () => childClass() // Passes own constructor for use in clone

    @override
    Map<String, dynamic> toMap() => {
      "foo":foo,
      "bar":bar,
      "x":x
    };
}

This allows childClass.clone to automatically return childClass(kwargs: toMap) no matter what childClass, as long as its specified again in the constructor. Still requires extra work but ensures no variance in how cloning operates.

Seems a little dirty to me so open for suggestions to optimize.