Home > Enterprise >  How to give child class property a different type from the superclass in Dart?
How to give child class property a different type from the superclass in Dart?

Time:10-03

I am in a situation where I'm working with entities and models. Basically my entities describe how my data should look like, and my models extends those entities and have a function toMap to transform them into a json object.

So I have 2 entities, Car and Brand, and one of the Car properties is of type Brand.

class Car {
  final String name;
  final Brand brand;

  const Car({
    required this.name,
    required this.brand,
  });
}

class Brand {
  final String label;
  final String color;

  const Brand({
    required this.label,
    required this.color,
  });
}

Then I have 2 models CarModel and BrandModel, which extends respectively Car and Brand.

class CarModel extends Car {
  CarModel({
    required String name,
    required BrandModel brand,
  }) : super(
          name: name,
          brand: brand,
        );

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'brand': brand,
    };
  }
}

class BrandModel extends Brand {
  BrandModel({
    required String label,
    required String color,
  }) : super(
          label: label,
          color: color,
        );

  Map<String, dynamic> toMap() {
    return {
      'label': label,
      'color': color,
    };
  }
}

As you can see, in CarModel, I would like the brand property to have a type BrandModel. However, it takes its superclass type.

So in the end, the brand property in my CarModel has a type of Brand.

My problem is that in the toMap function, I would like to use brand.toMap like so:

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'brand': brand.toMap(), // <= I want to use toMap() here, so I need brand to be of type BrandModel 
    };
  }

Is there a way to force my child class to have a different type for a property inherited from the superclass?

CodePudding user response:

Interesting problem. You are trying to achieve inheritance. So, what is happening when you are providing required BrandModel brand, in the constructor of CarModel which extends Car having final Brand brand; type of field. Brand get the necessary attributes/definition from BrandModel object, and it is the only reason that your are unable to call 'brand': brand.toMap(), inside the Map<String, dynamic> toMap() method bacause Brand class does not have this method.

Child has all the attributes/functions/definition of Parent but Parent does not possess all the properties of child.

SOLUTION

So, you need to put the toMap() in the Brand class. Here Abstraction comes in. At this stage, might be the toMap() method is unclear to you like what will it have inside the body, what will it map? Simply, declare it as abstract. Also, declare the class as abstract class. abstract class should have on abstract method.

Now, Polymorphism comes in. Inside the BrandModel class, the toMap() method will be an override method. Check the following tested code (complete example).

class Car {
  final String name;
  final Brand brand;

  const Car({
    required this.name,
    required this.brand,
  });
}

abstract class Brand {
  final String label;
  final String color;

  const Brand({
    required this.label,
    required this.color,
  });
  Map<String, dynamic> toMap();
}

class CarModel extends Car {
  CarModel({
    required String name,
    required BrandModel brand,
  }) : super(
          name: name,
          brand: brand,
        );

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'brand': brand.toMap(),
    };
  }
}
class BrandModel extends Brand {
  BrandModel({
    required String label,
    required String color,
  }) : super(
          label: label,
          color: color,
        );

  @override
  Map<String, dynamic> toMap() {
    return {
      'label': label,
      'color': color,
    };
  }
}

void main() {
  BrandModel brand = BrandModel(label:'Test',color : 'white');
  
  CarModel car = CarModel(name: 'T',brand : brand);
  
  print(car.toMap());
}

  • Related