Wird OOP einfacher oder schwieriger? [geschlossen]


36

Als die Konzepte der objektorientierten Programmierung vor Jahren den Programmierern vorgestellt wurden, sah es interessant aus und die Programmierung war sauberer. OOP war so

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);

Das war mit dem selbsterklärenden Namen leichter zu verstehen.

Aber jetzt ist OOP mit Mustern wie Datenübertragungsobjekten, Wertobjekten, Repository, Abhängigkeitsinjektion usw. komplexer geworden. Um dies zu erreichen, müssen Sie möglicherweise mehrere Klassen erstellen (z. B. abstract, factory, DAO usw.) und mehrere Schnittstellen implementieren

Hinweis: Ich bin nicht gegen Best Practices, die die Zusammenarbeit, das Testen und die Integration erleichtern


23
Das Erstellen einer guten Softwarearchitektur war schon immer schwierig und wird es (höchstwahrscheinlich) immer sein.
Johannes

6
Ich würde addItemfür addund removeItemfür umbenennen remove. Weil es leichter zu lesen ist. stock.add(item)oder stock.remove(item). Und mehr OOP orientiert.
Razpeitia

1
Original OOP sah fast nicht so aus wie das, was Sie gezeigt haben. Bei OOP geht es nicht um Syntax , sondern um eine Art Abstraktion, die von Smalltalk populär gemacht wird. Dies beweist nicht unbedingt, dass Ihr Standpunkt falsch ist, und die Prämisse ist auch nicht fehlerhaft. Vielmehr ist es sogar wahrer, als Sie erkennen.
Konrad Rudolph

1
Wenn Sie Äpfel und Orangen vergleichen, ist die zwingende Programmierung (dh Schleifen und If-Bedingung) nach Ihrer Logik einfacher als alle Dinge, die wir heute haben. Imperative Programmierung sind die Bausteine ​​für Klassen / OOP und Klassen / OOP sind die Bausteine ​​für Entwurfsmuster. Die Dinge werden komplexer, wenn Sie Fortschritte machen, weil Sie komplexere Probleme lösen.
Lie Ryan

2
@LieRyan - Ich habe gesehen, wie Probleme komplex wurden, nur weil niemand in der Lage war, sie mit einfacher Imperativprogrammierung zu lösen und sie mit Designmustern zusätzlich zu der einfachen Imperativlösung anzugreifen, die allein hätte implementiert werden müssen.
mouviciel

Antworten:


35

OOP selbst hat sich seit seiner Gründung nicht wesentlich verändert. Ein paar neue Blickwinkel wurden untersucht, aber die Kernprinzipien sind immer noch dieselben. Wenn überhaupt, macht das im Laufe der Jahre gesammelte kollektive Wissen das Leben des Programmierers eher einfacher als schwieriger. Designmuster sind kein Hindernis. Sie bieten eine Toolbox mit Lösungen für Standardprobleme, die auf jahrelanger Erfahrung basieren.

Warum empfinden Sie OOP heute als komplexer als zu dem Zeitpunkt, als Sie damit angefangen haben?

Ein Grund kann sein, dass der Code, dem Sie ausgesetzt sind, komplexer wird - nicht, weil OOP komplexer geworden ist, sondern weil Sie auf der Lernleiter Fortschritte gemacht haben und größere und komplexere Codebasen lesen können.

Ein weiterer Grund kann sein, dass sich das Komplexitätsparadigma zwar nicht geändert hat, die Größe und Komplexität eines durchschnittlichen Softwareprojekts jedoch sehr wohl. Mit der Rechenleistung, die auf Mobiltelefonen für Kunden verfügbar ist, die vor weniger als zwei Jahrzehnten ein feuchter Traum für Entwickler auf einem Server gewesen wären, rechnet die breite Öffentlichkeit im Grunde genommen mit raffinierten animierten Benutzeroberflächen für selbst die billigste Einweg-App und leistungsstärkeren Desktop-PCs der Einstiegsklasse Es ist nur natürlich, dass die Messlatte seit den Anfängen von Smalltalk und C ++ höher gelegt wurde als bei einem "Supercomputer" aus den 1980er Jahren.

Hinzu kommt, dass in modernen Anwendungen Parallelität und Parallelität eher die Norm als die Ausnahme sind und Anwendungen häufig zwischen verschiedenen Computern kommunizieren müssen, um eine ganze Reihe von Protokollen auszugeben und zu analysieren. Obwohl OOP als Organisationsparadigma großartig ist, hat es wie jedes andere Paradigma seine Grenzen: Zum Beispiel bietet es nicht viel Abstraktion für Parallelität (die meisten Implementierungen sind mehr oder weniger ein nachträglicher Gedanke oder wurden vollständig an Bibliotheken ausgelagert). und es ist nicht der bestmögliche Ansatz zum Erstellen von Parsern und zum Transformieren von Daten. Moderne Programmierung stößt häufig an die Grenzen des OOP-Paradigmas, und Entwurfsmuster können Sie nur so weit führen. (Persönlich, Ich betrachte die Tatsache, dass wir Entwurfsmuster benötigen, als ein Zeichen dafür - wenn das Paradigma diese Lösung sofort bereitstellen würde, wäre dies für diese Probleme aussagekräftiger, und die Standardlösungen wären offensichtlich. Es gibt kein Entwurfsmuster zur Beschreibung der Methodenvererbung, da dies ein Kernmerkmal von OOP ist. Es gibt jedoch ein Factory-Muster, da OOP keine offensichtliche natürliche Methode zum polymorphen und transparenten Konstruieren von Objekten bietet.)

Aus diesem Grund enthalten die meisten modernen OOP-Sprachen Merkmale aus anderen Paradigmen, wodurch sie ausdrucksvoller und leistungsfähiger, aber auch komplexer werden. C # ist das beste Beispiel dafür: Es hat offensichtliche OOP-Wurzeln, aber Features wie Delegaten, Ereignisse, Typinferenz, Variantendatentypen, Attribute, anonyme Funktionen, Lambda-Ausdrücke, Generika usw. stammen aus anderen Paradigmen, insbesondere der funktionalen Programmierung .


Also fügten Designmuster die Komplexität hinzu. Das bedeutet, dass Entwurfsmuster nicht unbedingt OOP sind, sondern hinzugefügt werden, um OOP zu verbessern.
Tunmise Fasipe

@tunmisefasipe: Nicht ganz. Entwurfsmuster sind nur bewährte Lösungen für Standardprobleme. Sie sind keine „Ergänzung“ zu OOP, sondern eine Konsequenz. Die Komplexität war schon da; Design Patterns bieten lediglich Kochbuchstrategien, um dies in Angriff zu nehmen.
Tdammers

17

Nein, es wird mehr überarbeitet. Und Sie haben Recht - im SO C ++ - Chat scherzen wir häufig über die AbstractSingletonFactoryProxyBeanBridgeAdapterManager, die wir im Java-Code sehen.

Guter Code weist diese Eigenschaft jedoch nicht auf. In gutem Code kann man noch sagen

std::stack<int> s;
s.push(5);
s.pop();

4
Nicht klar aus Ihrem Beitrag, aber ich denke, die Überentwicklung ist sowohl in Java als auch in C ++ offensichtlich . Es ist keine Eigenschaft einer Sprache für sich, sondern eine Eigenschaft der Programmierer. Beide Sprachen ermöglichen das Schreiben von gutem Code, obwohl keiner (IMO) besonders dafür geeignet ist.
Andres F.


3
@AndresF. stimmt, aber in C ++ erhalten Sie anscheinend nicht so viel davon, wie in Java und .NET: Sehen Sie sich nur das MVVMVMMD-Entwurfsmuster msdn.microsoft.com/en-us/magazine/hh965661.aspx an Ein Beispiel dafür, wie Sie "einfachen Code" nehmen und ein Entwurfsmuster darauf platzieren, um es "einfacher" aussehen zu lassen, und dann ein anderes Entwurfsmuster auf das Entwurfsmuster platzieren, weil das ursprüngliche Muster nicht so einfach war wie beworben. Überengineering wird immer alltäglicher.
gbjbaanb

5
Ich würde mit dem "Werden" -Bit streiten. Überengineering ist so alt wie Engineering.
Gort the Robot

4
@AndresF. Wir sind besonders gegen Java im Chat, aber es ist wahr, dass Java, mehr als C ++ , Überentwicklung fördert, weil es günstiger (GC) ist und beliebte Enterprise Java-Bibliotheken diesen Stil bekannt gemacht haben, wie Sie bemerkt haben du selber.
Konrad Rudolph

10

Ich würde sagen, dass die von Ihnen erwähnten Probleme mit "Komplexität" nichts mit OOP zu tun haben. Es hat mehr mit der Trennung von Bedenken zu tun.

Vor vielen Jahren habe ich an einem System gearbeitet, bei dem die Domainklasse die Verantwortung hatte, sich selbst aus der Datenbank zu laden, z

var userId = Request.QueryString["UserID"].ToInt();
var user = new User(userId);
user.Name = ...;
...
user.Save();

Das ist sehr klarer Code. Kein Problem, dies zu verstehen. Das Problem wäre jedoch das Testen des Codes in einer Einheit. Wie würde ich die UserKlasse testen , ohne eine aus der Datenbank laden zu müssen? Und wie würde ich diesen Code zur Bearbeitung von Webanfragen testen, ohne Zugriff auf die Datenbank zu haben? Es ist einfach nicht möglich.

Aus diesem Grund haben wir ein Muster wie ein Repository, um die Verantwortung für den Umgang mit der Domänenlogik eines Benutzers von der Funktionalität des tatsächlichen Ladens und Speicherns einer Domäne in einem Datenspeicher zu trennen. IOC hilft dabei, die Kopplung zu verringern und den Code testbarer zu machen.

Wenn wir also zu dem Beispiel zurückkehren, das Sie schreiben, was würden Sie mit dem Bestand tun, nachdem Sie ihn erstellt haben? Speichern Sie es in der Datenbank

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);
this.StockRepository.Add(stock);

Der Rote! Es gibt keine Bewegung in der Entwicklung von OOP, die darauf hindeutet, dass es schwieriger sein sollte. Wenn Sie einen OR-Mapper für Ihren Datenzugriffscode verwenden, kann das Problem auftreten, dass der OR-Mapper Einschränkungen für das Schreiben Ihres Systems enthält. Aber das ist eine andere Sache.

Wenn Sie mit diesen Mustern noch nicht vertraut sind, müssen Sie möglicherweise einen neuen Programmierstil erlernen. Diese Art der Programmierung ist jedoch keineswegs schwieriger als die OOP-Programmierung der alten Schule.


Sie kennen den Aufwand, den Sie für die Einrichtung Ihres Repositorys leisten müssen. Nach dem Einrichten ist es jedoch wieder verwendbar.
tunmise fasipe

Vielleicht liegt das Problem beim Unit-Testen darin, dass wir Systeme mit weniger Fehlern hätten, wenn wir bessere Tools hätten, um das Ganze zu testen (wie Sie es sowieso müssen), anstatt die winzigen Teile.
gbjbaanb

2
@gbjbaanb: Das haben wir bereits, es heißt Integration / Functional Testing. Unit Testing dient einem anderen, aber ebenso notwendigen Zweck
Kevin

@gbjbaanb - Wir haben bereits großartige Tools für systemweite / Akzeptanztests, z. B. Cucumber on the Rails-Plattform. Aber die Teams, die wirklich gut sind und sehr wenige Bugs schreiben, aber auch schnell liefern, schreiben viele Unit-Tests und nur ein paar systemweite Tests. Siehe zum " Testdreieck
Pete

4

Weder. Unsere Probleme haben sich nicht wirklich geändert. Die Messlatte für akzeptablen Code wurde angehoben.

Um dies zu erreichen, müssen Sie möglicherweise mehrere Klassen erstellen (z. B. abstract, factory, DAO usw.) und mehrere Schnittstellen implementieren

Sie müssen nicht haben , das zu tun. Aber wenn nicht, treten Probleme auf. Probleme, die immer da waren. Jetzt haben Programmierer jedoch genug Erfahrung, um diese Probleme zu identifizieren und Mechanismen bereitzustellen, um sie zu lindern (falls erforderlich). Wir lernen mehr darüber und finden bessere Lösungen (siehe - Ansichten der Programmierer zum Beispiel zum Singleton).

Man muss sich aber auch darüber im Klaren sein, dass die Einführung von Programmierern in OO (oder was auch immer) dazu neigt, die außergewöhnlichen Umstände zu verschleiern. Es ist einfach einfacher, den glücklichen Weg zu erklären und sich um den Rest zu kümmern, wenn die Anfänger das nicht wissen. Es gibt keine silberne Kugel; also ja, ich nehme die Dinge immer scheinen schwieriger , wenn der idyllische Wahn gebrochen ...


3

Die "Intro to OO" -Beispiele sind viel einfacher als eine reale Anwendung. Sie benötigen nur eine Klasse, um die oben genannten Ziele zu erreichen. Das Problem ist, dass es nicht viel bringt. Einige Entwurfsmuster (z. B. ActiveRecord) versuchen, einander nahe zu kommen. Letztendlich wird jedes Beispiel, das nicht trivial ist, mehr als eine Klasse haben. das ist ok.


Beachten Sie auch, dass sich mit der Zeit Frameworks aufbauen. Ja, Programmierung erfordert mehr Wissen. Dies bedeutet auch, dass man in kürzerer Zeit mehr erreichen kann.
Jeanne Boyarsky

3

Die Programmiersprachen, die heute OO verwenden, versuchen, komplexen Anforderungen und sich ständig ändernden Umgebungen gerecht zu werden. OO ermöglicht seinen Anwendern, verschiedene Komplexitätsebenen (unter anderem) auszublenden, damit die Codierung klarer und einfacher zu erstellen und zu verstehen ist. Diese Funktion ist jedoch nicht immer sofort einsatzbereit. In Ihrem Beispiel hat OO Ihnen ermöglicht, einige Details vor mir zu verbergen, indem Sie eine Methode zum Verwalten von Elementen in einer Sammlung bereitgestellt haben. Möglicherweise können Sie diese sogar mit der Methode "AddItem" beibehalten. Der Aufwand, Komplexität zu verbergen, kann zu einer einfachen Verwendung und einem wiederverwendbaren Framework führen, das das Leben einfacher macht. Bei vielen ORM-Implementierungen können Sie beispielsweise mit Datenbanken kommunizieren, ohne dass der Programmierer die SQL-Details schreibt. Dies ist in der Tat mächtig und macht es für den Entwickler einfacher.

Die Muster, auf die Sie sich beziehen, sind genau das. Sie sollen Ihnen das Leben erleichtern. Aber es liegt an Ihnen, sie zu übernehmen und anzupassen. Die Tatsache, dass mehr Arbeit erforderlich ist, liegt nur daran, dass Sie mehr Nutzen daraus ziehen. Es ist, als würde man für einen Ferrari mehr bezahlen. Wenn Sie die Extras möchten, zahlen Sie dafür. Wenn Sie sich also für den Aufbau einer skalierbaren N-Tier-Lösung entscheiden, die auf mehreren Servern und verschiedenen Back-End-Datenbanken ausgeführt werden kann, fallen hierfür Kosten an. Wenn Ihre Anwendung diese Komplexität nicht erfordert, ignorieren Sie die zusätzlichen Teile und greifen Sie auf die einfachste Lösung zurück, die Ihren Bedarf abdeckt (KISS & YAGNI).

Um es zusammenzufassen, ich denke nicht, dass OOP als Konzept selbst komplexer wird, wir, die Benutzer von OOP, haben die Wahl, es auf verschiedene Arten zu verwenden, und das ist eine gute Sache.


Klare Punkte. Ich kenne YAGNI. Was ist KISS?
tunmise fasipe

2
@tunmisefasipe, KISS ist eine Kurzbezeichnung für ein Designprinzip. Die ursprünglichen Wörter lauten "Keep It Simple (Stupid)" (ref: en.wikipedia.org/wiki/KISS_principle ), aber eine höflichere Formulierung könnte "Keep It So Simple" sein.
NoChance

3
@tunmisefasipe - KISS = Halte es einfach, dumm. Ein Satz, den ich mir selbst wiederhole, immer wieder und immer wieder, und der scheint immer noch nicht aufzugehen.
Michael Kohne

@MichaelKohne, das machen wir alle! Ich denke, es ist eine Kunst, Dinge zu vereinfachen. E = M C C sagt eine ganze Menge in einer sehr kurzen Form!
NoChance

3

Kurze Antwort : Ja, weil Sie sich mit schwierigeren Problemen auseinandersetzen.

Lange Antwort (stark voreingenommen) : Für mich deuten die Entwurfsmuster normalerweise darauf hin, dass einige Paradigmen Probleme in einem bestimmten Bereich haben. Die OOP-Muster befassen sich mit Problemen von OOP (auf einer niedrigeren Ebene befassen sich die Java-Muster mit Problemen von Java), FP-Muster befassen sich mit Problemen von FP usw.

Während der Programmierung können Sie unterschiedliche Prioritäten haben. Möglicherweise möchten Sie ein korrektes Programm, eine kürzere Markteinführungszeit, ein schnellstmögliches Programm, eine langfristige Wartbarkeit oder eine sofortige Wartbarkeit durch einen neuen Mitarbeiter. Abhängig von der Buschigkeit, in der Sie sich befinden, haben Sie ganz andere Möglichkeiten - wenn Sie die Steuerung eines Kraftwerks programmieren, möchten Sie dies gleich beim ersten Mal richtig machen und nicht jedes Mal ab und zu Fehlerbehebungen vornehmen ("Tritt bei jedem Drücken eine Kernschmelze auf Ctrl+Alt+Del?"). Wenn Sie sich in HPC befinden, kann die Logik relativ einfach sein, aber Sie möchten sie so schnell wie möglich ausführen usw. usw. Außerdem passen einige Paradigmen besser zu bestimmten Problemen (z. B. AI- und Logikprogrammierung, Daten- und relationale Datenbanken).

OOP ist in einfachen Fällen bis zu einem gewissen Grad "zu gut" und es handelt sich um die "Modellierung einer echten Live" -Geschichte. Zum Beispiel in dem ersten Buch über OOP mich gelesen gab es Klassen Person, Employeeund Managermit is-aBeziehung. So weit so gut, aber was ist, wenn ein Mitarbeiter zum Manager befördert wird?

Auf der anderen Seite haben andere Paradigmen einen schwierigeren Erstunterricht - zum Beispiel FP mit unveränderlichen Variablen (lustig ist, dass Menschen, die Erfahrung mit Programmieren haben, es oft schwerer haben zu lernen als diejenigen, für die dies die Muttersprache ist) - aber letztendlich sind sie es nicht härter als OOP. Das Testen von reinen Funktionen ist trivial und in Haskell / Scala / ... haben Sie Tools, die Tests für Sie generieren.

PS. Ja - die Antwort ist voreingenommen gegenüber OOP und ich gebe zu, dass sie in gewissem Maße eine Reaktion auf OOP darstellt. OOP hat seinen Nutzen, aber es ist meiner Meinung nach nicht die einzige, ultimative Lösung.

PPS. Ja - verwenden Sie Entwurfsmuster - sie machen die OOP-Programmierung letztendlich einfacher.

PPPS. Ich habe OOP als Synonym für imperative OOP-Programmierung verwendet.


2

Ich denke, es ist eher so, dass die Dokumente und Beispiele realistischer werden.

Frühe OOP-Bücher (insbesondere frühe Java-Bücher) zeigten eine absurd vereinfachte Ansicht der Anwendungsprogrammierung. Die Beispiele "Ein Bankkonto mit einem 10-Zeilen-Java-Programm belasten" waren immer besonders ärgerlich, da ich Beispiele aus der Praxis für diese einfache Aufgabe mit 6000 Zeilen COBOL-Code gesehen habe (und den Java-Ersetzungsversuch mit 3500 Zeilen, bevor er abgebrochen wurde) als undurchführbar!).

Zum Glück erkennen OO-Bücher die Komplexität des wirklichen Lebens an und bieten nützliche Beispiele für den Umgang mit ihnen.

Aber wenn Sie sehen möchten, wie man ein Bankkonto in nur 15 Zeilen Code- Funktionsprogrammierung verwaltet, sind Sie hier richtig

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.