OO design: general handling of subclasses that introduce new fields

This is a design problem that I encounter all the time, so I thought that I would finally post it there and see how people pick it up. The problem is this:

I identify a specific class, which for the most part describes all instances of objects that I will use, both behavior and data. This is great and works well for basic objects. Then there are several other types of objects that need the same data and behavior, but would also like to have an additional field here and there or an additional data structure.

Call the Something class:

public class Something { private int id; private String fieldA; private String fieldB; private List<Data> list; // Then we have getters, setters, and some base methods } 

Sometimes we need to use SomethingElse and SomethingDifferent. They are 90% similar to the fact that the same data and behavior describe them, however they additionally have additional fields that should be used by the rest of the program:

 public class SomethingElse extends Something { private String dataSpecificToSomethingElse; // Then we have getters, setters, and some new-data specific methods } public class SomethingDifferentextends Something { private List<DifferentData> dataSpecificToSomethingDifferent; // Then we have getters, setters, and some new-data specific methods } 

I would like to come up with a decent way to handle the Something family of objects in a generic OO style, since I would not want to associate the rest of my application with specific implementation details (because we might need to add SomethingWacky later). I don’t want to deal with subclasses directly, as this breaks the polymorphism and will probably include the need to lower / make a switch like - yuck.

The approaches that I can solve for this are as follows:

  • Create an abstract base class that defines all the methods for the Something family. Then the children implement only the behavior that they relate to the provision, leaving the NOP / blank override for methods that do not present a problem. This allows everything to be handled the same, but introduces an interface bloat.
  • Transfer responsibility to the base class through common working methods, following Tell, Don't Ask . For example, it could be things like display (), doWork (), persist (), getStateFromDisplay (), etc. Each subclass will take its data into account when overriding these basic methods. I recently read an article by Allen Holub, which suggested that this might be good practice. This seems like too much responsibility for the external problems for the class.
  • Create a data class that groups all the extra data / behavior from subclasses and references this in Something. This is not very similar to OO-like.

I used approach 1 during the previous project, but in this case, despite the fact that each subclass only implemented / redefined the methods he cared for, the operations were generalized enough, so it was plausible that the class could execute all or only some .

Each approach seems messy in some way, and I really don't like it. What are my alternatives? Perhaps I am completely abusing inheritance or completely approaching this. I am open to any suggestions and would like to use OO methods to come up with cleaner, decoupled constructs. I would really like to know how people solved such problems, and any resources that you could refer to me would be very grateful.

thanks

+6
source share
3 answers

When it becomes necessary to add SomethingElse , SomethingDifferent , etc., I would ask: should SomethingElse really be able to individually access all the elements of Something data and behavior? Or is its use of Something limited to several methods?

If this is the latter, it is usually recommended to encapsulate the specific Something behavior, which is often used by other classes, and then use composition rather than inheritance .

+3
source

These are very interesting questions and I must admit that I often come across the same problem.

All you said is that they are all valid, and the idea of ​​a subclass is really designed to solve the problems you just described. Using ABC is a good OO principle, so I suggest you study this a bit more. However, in terms of defining all the method interfaces in the base class, you will need to reevaluate this. First, I think you should take a step back and ask the main OO question about whether all these behaviors apply to an object of this type? I also think that based on the volatility of your domain model, you will know all the possible behaviors up or right now or else you probably do not have the problem that you just described.

I think you can use the above approach to reorganize your inheritance tree and in combination with the Decorator design pattern to separate your implementation and ensure the stability of your inheritance tree and allow extensions through the decorator classes.

+1
source

You may have a set of interfaces describing the various use cases that appear in your application. The principle separates the principle of separation and the principle of shared responsibility . I think the best way to achieve code reuse is to keep your classes as small and focused as possible and use composition rather than inheritance to delegate some of these interface implementations.

0
source

Source: https://habr.com/ru/post/894688/


All Articles