When designing a game, a question arose. Suppose there is an IUnit interface and it is implemented by all the classes that describe the units. But for these classes, some of the code may be the same, therefore, or you will have to duplicate the code, which simply contradicts the purpose of the functions, or add default behavior.

I decided to do this: the interface remains, but the abstract UnitBase class is UnitBase , which implements the default behavior for some methods, and already classes describing the units either explicitly implement the interface if they are not at all like UnitBase or inherit UnitBase to avoid code duplication.

However, there is an opinion that inheritance breaks encapsulation, therefore inheriting an abstract class is bad and my approach is unsuitable. Is this true and how this architecture corresponds to the canons of the PLO?

  • Why are you afraid to make a couple of abstract intermediate classes? If the code is correctly expanded on them, then everything will be simple and beautiful. - KoVadim
  • @KoVadim that is, inheritance does not violate encapsulation (in this case or in general (if in this, which product violates))? - wcobalt 6:55 pm
  • one
    use private, protected and public, and neatly divide the access to the data - and encapsulation will not suffer. - KoVadim 7:09 pm
  • In the game, besides the abstract class, nodal classes are more likely to be needed, but the game is better built on the basis of concrete classes ... - AR Hovsepyan
  • Maybe you still need to think about aggregation. As for inheritance: you need to think carefully about what functionality you give to the base abstract class, and which classes to the heirs. - Unick

1 answer 1

The proposed approach is quite consistent. The desire to eliminate duplication is commendable and should be encouraged.

By and large, if the default behavior that will be in UnitBase may not be suitable for some units, then the name probably should not be UnitBase , but be more specific, for example, GroundUnit , AirUnit , etc.

In general, due to the fact that in C ++ there are no true interfaces (as in Java or C #), the separation of IUnit and UnitBase , provided that the meaning of the previous paragraph is respected, is not necessary in principle. It is enough to have at least one purely virtual function in the class in order to prohibit its instantiation without implementing an explicit heir.

there is an opinion that inheritance violates encapsulation

A strange opinion, it would be nice to know where you heard it. Encapsulation is the concealment of data and the provision of access to it through public functions combined with this data in one framework (class). If the concealment is implemented correctly, the use of public functions does not violate the class invariant, and the public inheritance of classes adheres to the principle “an object of a derived class is an object of the base class”, then no encapsulation violations can be made.

Another thing is that inheritance makes the architecture more rigid, if the class is designated as the heir of another class, this relationship can no longer be changed in dynamics. Therefore, it is often possible to hear suggestions for replacing inheritance with aggregation. Those. Add an IBase* type field to the class and it will be possible to change this pointer in runtime, providing different behavior, depending on the specific instantiated class.

  • Read about "inheritance breaks encapsulation" here m.habr.com/post/30444 - wcobalt
  • one
    @wcobalt notice the comment there. - αλεχολυτ 7:34 pm