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());
}