Hallo Tom,
Ich möchte hier mal für's Archiv eine Lanze für OOP brechen. Oder besser gesagt: Für strukturierte Programmierung allgemein, wo OOP nur ein bekannter Vertreter ist (es gibt auch andere Paradigmen). Du schreibst, dass Dir höhere Sprachen suspekt sind, weil sie für einfache Konstrukte, wie zum Beispiel schleifen, zu viele Operationen durchführen und damit komplett ineffizient sind.
Ich möchte Deiner Schlussfolgerung, dass sie aus diesem Grund ineffizient sind, komplett widersprechen. Das Problem 99% aller Software ist nämlich nicht, wie lange eine einzelne Instruktion braucht. Ob eine Schleife vom Compiler totoptimiert wird oder nicht ist für die meisten Anwendungen vollkommen uninteressant.
Betrachten wir zum Beispiel eine Suchfunktion einer Webseite. Betrachten wir folgende beide Herangehensweisen:
-
Man nimmt eine klassische, lineare Suche, die alle zu durchsuchenden Dateien einliest und nach den Suchbegriffen nacheinander sucht. Man optimiert den Assembler-Code auf Mikroebene, dass alle Schleifen und Instruktionen so schnell wie es nur möglich ist ausgeführt werden.
-
Man überlegt sich eine brauchbare Suchindexstruktur und schreibt die Suche in einer sehr abstrakten Hochsprache (Java, Python, Ruby, whatever) und optimiert die einzelnen Instruktionen überhaupt nicht. Allerdings steckt man viel Aufwand in die Auswahl der Indexstruktur etc.
Ich garantiere Dir, dass bei nichttrivialen Datenmengen die zweite Version in einer Hochsprache der Assembler-Version um mehrere Größenordnungen schneller ist. Nicht, weil die Hochsprache irgendwie schneller oder besser wäre als Assembler. Aber weil ein brauchbarer Suchindex weitaus mehr ausmacht, als Mirkooptimierung von Prozessorinstruktionen.
Natürlich könnte man auch einen Suchindex in Assembler nachbauen, aber das würde einen sehr hohen Entwicklungsaufwand nach sich ziehen. Einfach weil es in Assembler weitaus aufwändiger und schwieriger ist, abstrakte Ideen umzusetzen, als in einer Hochsprache, die Abstraktionskonzepte bereits mit sich bringt.
Man mag einwenden, dass das Suchindexbeispiel vielleicht nicht unbedingt ein Paradebeispiel für OOP an sich ist, aber es verdeutlicht zumindest mal, warum Optimierung auf einer höheren Ebene für die meiste Software viel wichtiger ist, als Mirkooptimierung. Die ist für fast jede Software vollkommen uninteressant.
Es gibt jetzt nun in meinen Augen zwei extrem gute Gründe, warum OOP ein sehr hilfreiches Konzept ist:
1. Es bietet eine ausreichend abstrakte Ebene, um Dinge darzustellen und ermöglicht es so, sich auf die wesentlichen Aspekte eines Algorithmus zu konzentrieren.
2. Es ermöglicht, Code auf mehrere Arten wiederzuverwenden.
Zum Punkt 1: Ich kann Code sehr gut kapseln, d.h. bestimmte Logik, die an bestimmten Stellen im Programm nicht interessiert, in andere Klassen kapseln. Damit hast Du sehr sprechenden Code (objekt.tuDies(), objekt.holeDas(), ...), der einem einen viel besseren Überblick über die Art gibt, wie der Code funktioniert.
Dies ist insbesondere bei der Wartung des Codes sehr wichtig, dass man den Code sehr schnell verstehen kann, auch wenn man ihn schon einige Zeit nicht mehr oder noch nie (wenn man neu hinzugekommen ist) gelesen hat.
Zum Punkt 2: Wiederverwenden von Code im OOP-Bereich funktioniert auf zwei verschiedene Arten:
Man kann Dinge in generische Klassen kapseln, die bestimmte Aufgaben erledigen. Paradebeispiel für den OOP-Einsatz sind GUIs: Ein Eingabefeld ist ein Objekt, ein Fenster ist ein Objekt, etc. Die zu Grunde liegenden Klassen kann man beliebig oft wiederverwenden für weitere Eingabefelder / Fenster / etc. im Programm. Wenn man an dem Aussehen oder Verhalten aller Eingabefelder etwas ändern will, muss man eine zentrale Klasse ändern.
Ferner gibt es in der OOP das Konzept der Vererbung: Man kann Klassen erzeugen, die von anderen Klassen erben und damit erst einmal alle Eigenschaften und Methoden übernehmen. Bestimmte Eigenschaften und Methoden kann man dann überschreiben, um in spezifischen Kindklassen ein anderes Verhalten zu erzeugen. Auch hier wäre die GUI ein Paradebeispiel: Es gibt eine allgemeine Klasse "Eingabefeld" und dann gibt es eine Klasse "ZahlenEingabefeld", die die mögliche Eingabe auf Zahlen beschränkt. Die meisten Eigenschaften beider Klassen sind gleich (wäre also doppelter Code, wenn man kein OOP einsetzt - und OOP-Einsatz heißt für mich auch, wenn man OOP in nicht-OOP-Sprachen wie C nachbildet), allerdings gibt es ein paar wenige Dinge, bei denen sich beide Eingabefelder unterscheiden. Und genau hier ist dann Code-Wiederverwendung sehr sinnvoll.
Wenn Du Dir dann noch überlegst, wie viel Zeit dabei verloren geht, Software zu erweitern und/oder zu debuggen, die solche Abstraktionen wie OOP eben nicht einsetzt, aber doch sehr komplexe Systeme umsetzt, dann geht Deine Milchmädchenrechnung, dass man durch OOP die Umwelt belastet, erst recht nicht auf, unabhängig von der Tatsache, dass Mirkooptimierungen meistens sowieso nicht viel ausmachen (siehe oben). Ja, ich weiß, das mit der Umwelt hast Du nicht ganz so gesagt, aber wenn Du schon Polemik einbringst, dann darf ich nachfassen. ;-)
Selbstverständlich gibt es auch Leute, die es stark übertreiben und alle möglichen Programme mit Features bis zum geht nicht mehr vollstopfen, die kein Mensch benötigt, und damit Ressourcen ohne Ende verschwenden. Oder Leute, die alles ZU generisch machen wollen und sich 5 Klassen anlegen, wo nur eine ausreichen würde, so dass keiner mehr durchblickt. Das ist aber kein grundsätzliches Problem von OOP, denn mit jedem Programmierkonzept kann man unsäglichen Mist bauen. Und deswegen ändert es nichts an der Tatsache, dass OOP ein sehr nützliches Konzept für sehr viele Anwendungsbereiche ist.
Natürlich gibt es auch Bereiche, in denen solche Konzepte nicht sinnvoll sind, nämlich genau dann, wenn hardwarenähe sehr wichtig ist. Dies ist vor allem bei Low-Level-Treibern der Fall, bei Anwendungen mit Echtzeitanforderung, im Embedded-Bereich (Mikrocontroller) und eben auch bei bestimmten kritischen Algorithmen, die besonders viele Daten möglichst schnell verarbeiten können sollen, wie zum Beispiel Verschlüsselungsalgorithmen für SSL oder Festplattenverschlüsselung oder ähnliches. Dies macht jedoch von der tatsächlich entwickelten Software nur einen geringen Teil aus und wenn man so etwas macht, dann programmiert man auch ganz anders, als wenn man normale Software programmiert. Und gerade z.B. Treiber oder Verschlüsselungsalgorithmen: Die werden idR. von Experten programmiert und von normaler Anwendungssoftware nur eingebunden und genutzt, so dass man die Vorteile aus beiden Welten hat.
Viele Grüße,
Christian