What are the disadvantages of using inheritance as a way to reuse code?

What are the disadvantages of using inheritance as a way to reuse code?

+4
source share
5 answers

Using inheritance to reuse code suffers from the following issues:

  • You cannot change reuse at runtime. Inheritance is a compile-time dependency, so if the GameClient class inherits from TCPSocket to reuse the connect() and write() member functions, it has a hard TCP encoding. You cannot change this at runtime.

  • You cannot replace reusable behavior from outside for testing. If the GameClient class inherits from TCPSocket , so that it gets write() (to write data to the socket), you cannot exchange this code externally. You cannot connect another write () function that logs all the data that GameClient wants to write to a file or so.

  • You are dependent on multiple inheritance for all but the simplest applications. This opens the door for rhomboid inheritance trees , which greatly increase code complexity.

The preferred composition over inheritance for code reuse avoids all of these problems.

+6
source

IIRC, The Liskov replacement principle 1) postulates that you need to substitute a class with any of its derived classes; that is, derived classes should not behave radically differently than or violate the contract created by their base classes.

Obviously, then this principle deliberately limits how a (base) class can be "reused" by another class (which is derived from it). Other uses of the class, such as aggregation or composition, are not limited to this principle.


1) See Liskov replacement principle (links to PDF document).

+6
source

Using inheritance means that when you call a method (or virtual method in C ++) in the same class, it does not immediately become clear that you can actually call the subclass method. The smell of code that can occur is a call stack that goes up and down the class hierarchy, which in fact means that your superclass and subclass are cyclically dependent.

Using composition and interfaces makes it clear that there are many possible implementations, and also makes it obvious when there is a circular dependency (which usually needs to be removed).

(Composition makes circular dependencies obvious for several reasons (assuming that you use class pass-dependencies through a constructor.) If A and B depend on each other, then either A builds B, or passes this or self to constructor B, which is explicit a sign of circular dependence or some other constructions of the classes of both A and B, which is impossible, since A requires B to be built first, and B requires A to be built first.)

+3
source

It requires inheritance (to reflect it), which is just one of many possible structures for the code. That is why we have procedural programming, functional programming, object-oriented programming, aspect-oriented programming, declarative programming, etc. See programming paradigms .

0
source

If you use inheritance, you become attached to an object-oriented stateful paradigm. If you try to use immutable objects, you will end up writing [pseudocode]

 class A (int X, int Y) def self.nextX(int nextX) = A(newX, self.Y) class B (int X, int Y, int Z) extends A(X, Y) def self.nextX(int nextX) = B(newX, self.Y, self.Z) 

and code reuse is not used. This way you use mutable objects and madness arises :).

0
source

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


All Articles