Gibt es in der OOP Nachteile der Vererbung und der Kapselung?

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Mir fallen spontan folgende Nachteile ein (die man aber im Hinblick auf die vielen Vorteile gerne in Kauf nehmen wird):

  • durch die Kapselung ist es evtl. für unerfahrene Entwickler anfangs etwas schwierig, vernünftige Tests zu implementieren (aber dafür gibts ja Mocks, also kein echtes Problem)
  • der Speicheroverhead bei abgeleiteten Klassen beträgt ungefähr so viel, wie ein Zeiger breit ist, also meist 4 bis 8 Byte. (Klingt wenig, aber wenn man hunderte Millionen von Flyweight-Objekten erzeugt, macht sich das deutlich bemerkbar.)
  • Bei Zugriffen über eine Art this-Zeiger, gibt es immer eine Indirektion, was Cache-Misses und damit Performanceeinbußen bedeutet. (Macht sich in der Praxis aber wirklich kaum bemerkbar.)

So, das wären jetzt die Haupteinschnitte, mit denen man bei OOP rechnen muss, aber wie gesagt, kann man die alle eigentlich vernachlässigen, da die Vorteile bei WEITEM überwiegen.

Außerdem bieten Sprachen wie C++ sehr elegante Entwicklungsmuster, mit denen man dynamisch mit abgeleiteten Klassen arbeiten kann, ohne dass ein herkömmlicher Objektzeiger notwendig wird.

Bei "gemanagedten" Sprachen, die mit einer Art GC arbeiten, muss man aber immer im Hinterkopf behalten, dass Objekte dort implizit VIEL größer sind und mehr Speicher fressen, als es den Anschein hat.

Wenn man z. B. bei Java eine Klasse hat, die eine einzige Membervariable vom Typ "byte" hat, dann frisst das Objekt auf x64-Systemen 20 Byte.

Der Grund ist, dass so ein Objekt auf dem Heap erzeugt wird, und auf dem Stack ein Zeiger bzw. eine Referenz liegt.

Java packt Zeiger seeeehr clever, sodass auf 64-Bit Systemen nicht 8 Byte, sondern nur 4 Byte verbraten werden. Das hat allerdings einen Preis: Eine weitere Indirektion beim Zugriff!

Naja, 4 Byte liegen also auf dem Stack, weitere 8 Byte werden für den internen Zeiger im Speichermanager der VM benötigt (diesmal ungepackt und direkt), dann gibt es einen Referenzzähler von nochmal 4 Byte.

Und da die Membervariable von einem Byte an ein Alignment gebunden ist, werden zusätzliche drei Byte verbraten, sodass wir hier auf 4 Byte kommen.

Deshalb ist ein 1-byte in Java 4 + 8 + 4 + 4 = 20 Byte groß.

Bei C++ würde das gleiche Objekt tatsächlich nur ein einziges Byte auf dem Stack verbrauchen, bzw. 1 Byte auf dem Heap und 8 Byte auf dem Stack bei x86, ... oooooder, wenn man es wie in Java mit eigenem Allokator nachbaut 1 Byte auf dem Heap und nur 1, 2, 3, oder 4 Byte auf dem Stack.

Aber in 99% aller Fälle muss man sich bei Kapselung in Kombination mit OOP um solche Dinge keine Gedanken machen. (Außer beim Aligning ... damit kommt man tatsächlich hin und wieder in Berührung.)

Alles in allem: OOP und Kapselung haben keine nennenswerten Nachteile. Und wenn man tatsächlich an Grenzen stoßen sollte, gibt es immer Mittel und Wege, diese zu umschiffen.

Woher ich das weiß:Berufserfahrung

Vererbung ist eine sehr starke und starre Kopplung von Klassen. Viele Dinge lassen sich sowieso nicht mit Einfachvererbung darstellen; Mehrfachvererbung macht aber auch jede Menge Probleme. Daher https://en.wikipedia.org/wiki/Composition_over_inheritance

Kapselung kann schlicht falsch gewählt sein - man kommt später drauf, dass gewisse Dinge doch nach außen sichtbar sein sollten.

Und natürlich hat das ganze OOP-Zeugs einen gewissen Overhead durch RAM und indirekten Funktionsaufruf. Meistens egal, manchmal nicht.