dimanche 18 juillet 2021

How to deal with base class methods that are incompatible with the derived class?

Imagine that you're making a GUI and have a DataViewList class that is a widget that displays rows of data (like this for example). You have methods AddRow(std::vector<std::string> row), DeleteRow(std::vector<std::string> row) and AddColumn(std::string name), DeleteColumn(std::string name).

Now lets say you want to make a new class that displays a music playlist. It has predetermined columns (Title, Album, Year) and you don't want to ever add any new columns or delete existing ones. Also you want to be able to add Song objects to the list in a single method call, so you need a method that can do that. How do you implement such a class?

The most basic idea is to just create a new class MusicPlaylsit that inherits publicly form DataViewList and add the predetermined columns in the constructor. Then overload the AddRow methods such that it accepts Song objects as an argument. This approach has a big problem: Someone could call MusicPlaylist::AddColumn or other methods that are incompatible with the logic of the MusicPlaylist class. Since MusicPlaylist should only ever have the three predefined columns, then there shouldn't be a way to add or delete columns (or access any other incompatible base class methods such as the base class non-overloaded AddRow method).

To solve this, I can use composition instead of inheritance and re-implement any methods that I may want to use. In my opinion this is a bad idea because if I want to change something in the future, it's more difficult than inheritance because I cant override the base class methods.

Another option is to inherit as protected. This prevents using incompatible base class methods AND allows for overriding in case of future inheritance. The problem is, now I have to explicitly declare every method I want to use as public with using, which seems to be against the whole point of object oriented programming (being able to change something in a deep base class and still have any inherited class be able to use it) because newly added public methods in DataViewList will not be visible in MusicPlaylist or any classes that inherit from it until they have been explicitly made public.

So my question is: which pattern should I use when creating a new class that has an "is a" relationship to a base class, but is only partially compatible with it's methods?

Thanks

Aucun commentaire:

Enregistrer un commentaire