Having the next classes as a simplifiacation of the issue:
struct Car
{
virtual int get_price() = 0;
};
struct ExpensiveCar: public Car
{
int get_price( ) {/*..*/ }
void apply_turbo( ){/*..*/};
};
struct CheapCar: public Car
{
int get_price( ) {/*..*/}
};
struct CarRetailer
{
virtual std::vector<Car*> get_cars( ) = 0;
};
struct ExpensiveCarsRetailer : public CarRetailer
{
virtual std::vector<Car*> get_cars( ) { /*..*/ }
std::vector<ExpensiveCar*> get_cars_for_exhibitions( );
};
struct CheapCarsRetailer : public CarRetailer
{
virtual std::vector<Car*> get_cars( ) { /*..*/ }
std::vector<CheapCar*> get_second_hand_cars( );
};
The rules are: Expensive Cars are only sold in ExpensiveCarsRetailers (similar for Cheap Cars ). Cheap cars do not have turbo and expensive cars are not sold in second hand.
The issue I face here is the coupling of classes that contains inherited classes as well. Therefore, if ExpensiveCarRetailer inherits from CarRetailer, it will need to implement virtual std::vector<Car*> get_cars( ) that is actually returning a vector of Car*, however, internally ExpensiveCarRetailer only created objects of ExpensiveCar. Furthermore, the get_cars_for_exhibitions() is not included in the public interface CarRetailertherefore, it can return a std::vector<ExpensiveCar*> instead.
The mixture in the API ( returning vector of Car* and ExpensiveCar* ) is very ugly, and so is the code that the user needs to write to use the apply_turbo( ) function of the list of cars from a specific ExpesiveCarsRetailer.
ExpensiveCarsRetailer ferrari;
std::vector<Car*> car = ferrari.get_cars();
ExpensiveCar* expensive_car;
for( int i = 0; i < car.size( ); ++i)
{
expensive_car = dynamic_cast<ExpensiveCar*>(car[i]);
expensive_car->apply_turbo();
}
I am sure I am missing some design pattern that helps in this situation, where to trees of class inheritances are coupled in a way that the abstract class of one of the inheritance tress need to return a vector (or set, list, etc ) of classes on the other inheritance tree. I am trying to avoid the dynamic casting as much as possible.
I also though on making CarRetailer a templated class, therefore:
template struct CarRetailer { virtual std::vector get_cars( ) = 0; };
And then make:
struct ExpensiveCarRetailer: public CarRetailer<ExpensiveCar>
{
...
}
But I don't think this would work since, for example, the CarRetailer can also start selling motorbikes ( similar structure as cars ) or bikes etc ( always applying the Expensive/Cheap pattern ) and eventually the number of template classes that need to be defined in CarRetailer will be huge.
Aucun commentaire:
Enregistrer un commentaire