OO ist gescheitert

Ist OO (definiert nach Alan Key) gescheitert?

  • JA

  • NEIN


Die Ergebnisse sind erst nach der Abstimmung einsehbar.

AndiE

Top Contributor
Da würde ich jetzt mal sehen, was primär der sekundär OOP ausmacht. Primär, im Sinne von Alan Key sind es kombinierte Objekte die Status und Verhalten besitzen, die per Nachrichten miteinander kommunizieren. Sekundär wird in Tutorials angeführt, dass OOP durch Vererbung, Kapselung und Polymorphie gekennzeichnet ist.

Wenn ich ein OOP-Projekt beschreibe, habe ich im Grundsatz immer eine statische Beschreibung und eine dynamische. Das kann man auch an den Diagrammtypen bei UML sehen. Statisch bedeutet dabei die Angabe, welche Klassen Objekte erstellen und wie diese miteinander zusammenhängen. Dynamische Beschreibungen zeigen dann, welches Objekt welche Nachricht an wen schickt.

Auch wenn man Methodenaufrufe der OOP mit Prozeduraufrufe der PP gleichsetzen kann, ist es doch im Sinne des Entwurfs was unterschiedliches.
***
Natürlich ist weder eine Generalisierung noch Spezialisierung zwingend notwendig, diese "Vererbung" vereinfacht aber die Bildung von Objekten sehr.

Wenn ich Nachrichten zwischen Objekten als Aufträge verstehe, dann macht es doch auch Sinn, wenn jeder seine Inhalte nicht einfach so nach außen sichtbar macht. Daher Kapselung.

Bei Polymorphismus ist es am schwierigsten, da ein sinnvolles Beispiel zu finden. "ZeigeKunde(int nr)" und "ZeigeKunde(int von, int bis)" wären doch zwei Funktionen die den selben Bezeichner haben, aber unterschiedliche Argumente- und damit polymorph. Oder?

Alles drei ist aber eben nicht zwingend OOP

***
Leider kenne ich mit domain-getriebener Entwicklung nicht so aus. Soweit ich das aber bis jetzt verstanden habe, werden dort die Datenobjekte in Factorys erzeugt und gehalten, die dann von Methoden-(Service-)Objekten benutzt werden. Und diese Trennung zwischen Daten und Verhalten erinnert eben sehr an PP.

Vielleicht sollte ich mich da mal tiefer reinlesen =)
 

mrBrown

Super-Moderator
Mitarbeiter
Natürlich ist weder eine Generalisierung noch Spezialisierung zwingend notwendig, diese "Vererbung" vereinfacht aber die Bildung von Objekten sehr.

Jein. Sie machen es leichter, es gibt aber auch genug Sprachen, die ohne Vererbung existieren.
Und in einigen Sprachen ist es auch nur eine Vererbung von Verhalten, aber nicht des Typs

Wenn ich Nachrichten zwischen Objekten als Aufträge verstehe, dann macht es doch auch Sinn, wenn jeder seine Inhalte nicht einfach so nach außen sichtbar macht. Daher Kapselung.

Die Definition von Kay ist sehr stark von Smalltalk beeinflusst, und dort sind alle Variablen ausnahmslos privat - mit Instanz-Score, nicht wie in z.B. Java mit Klassen-Scope.
Und in seiner Definition gibt es nur Messages zum kommunizieren, keinen Zugriff auf Variablen.

Bei Polymorphismus ist es am schwierigsten, da ein sinnvolles Beispiel zu finden. "ZeigeKunde(int nr)" und "ZeigeKunde(int von, int bis)" wären doch zwei Funktionen die den selben Bezeichner haben, aber unterschiedliche Argumente- und damit polymorph. Oder?
Nein. Polymorphie meint, das unterschiedliche Objekte auf die selbe Message unterschiedlich reagieren.
Das was du als Beispiel bringst, sind zwei unterschiedliche Messages, üblicherweise als Überladen bezeichnet.

Jedes Objekt bestimmt selbst, wie es auf eine Message reagiert - deshalb implizieren Messages auch Polymorphie.


Leider kenne ich mit domain-getriebener Entwicklung nicht so aus. Soweit ich das aber bis jetzt verstanden habe, werden dort die Datenobjekte in Factorys erzeugt und gehalten, die dann von Methoden-(Service-)Objekten benutzt werden. Und diese Trennung zwischen Daten und Verhalten erinnert eben sehr an PP.

Vielleicht sollte ich mich da mal tiefer reinlesen =)
Wenn das dein bisheriges Verständnis davon ist: ja, du solltest dich wirklich mehr reinlesen ;)

Das ist eigentlich genau das Gegenteil dessen, was du verstanden hast.
Es geht darum, die Trennung von Daten und Funktionen zu vermeiden - nicht sie herbeizuführen.
Datenobjekte gibt es dort nicht (soweit möglich, manche Dinge sind halt nur Daten [oder welches Verhalten hat z.B. eine Postleitzahl?]). Services gibt es auch nur, weil sich nicht jedes Verhalten eindeutig Domänen-Objekten zuordnen lässt, sie sind aber auch nicht nur eine Sammlung von Methoden, sondern haben durchaus auch State und sind Polymorph.
 

mihe7

Top Contributor
Primär, im Sinne von Alan Key sind es kombinierte Objekte die Status und Verhalten besitzen, die per Nachrichten miteinander kommunizieren

Ich verstehe leider nicht, worauf Du mit "primär" und "sekundär" hinaus willst.

Bei Polymorphismus ist es am schwierigsten, da ein sinnvolles Beispiel zu finden.

Warum? Dein Beispiel mit den Kalorien war ja schon gar nicht so verkehrt. Du hast nur den "Fehler" gemacht, Dich darauf zu konzentrieren, aus welchen Daten Du die Kalorien gewinnst.

Für die Berechnung der Gesamtkalorien des Speiseplans ist das aber völlig irrelevant. Du brauchst an der Stelle einfach Objekte, die Dir eine Kalorienzahl liefern, Thema erledigt. Ob das nun ein Objekt ist, das intern die kcal/100g speichert und auf die übliche Portionsgröße umrechnet, ob die kcal/Portion direkt gespeichert und einfach zurückgegeben werden, ob das Objekt die kcal aus den Mengen an Kohlenhydraten, Fetten und Eiweißen berechnet oder die kcal aus dem Kaffeesatz liest: völlig egal. Und das ist der Punkt, der in PP nicht (ohne weiteres) funktioniert.
 

AndiE

Top Contributor
@mrBrown: Ich habe im Netz Tutorials von 2009 gefunden, die einen eigenen Service-Layer bei DDD als typisch angegeben haben. Das ist eben ganz anders als in einem Buch von 2013, wo genau dieses Verfahren als "blutleer" bezeichnet, und abgelehnt wird.

Zur anderen Frage: Es wurden vor Jahren die verschiedenen Aufrufe der print-Methode in Büchern als Beispiel für Polymorphie genannt, obwohl es dabei ja eher um Overloading geht.

Darum halte ich eben für wichtig, abzuklären, was die Poster mit den Begriffen meinen, die sie verwenden.
 

mrBrown

Super-Moderator
Mitarbeiter
@mrBrown: Ich habe im Netz Tutorials von 2009 gefunden, die einen eigenen Service-Layer bei DDD als typisch angegeben haben. Das ist eben ganz anders als in einem Buch von 2013, wo genau dieses Verfahren als "blutleer" bezeichnet, und abgelehnt wird.
Und ich habe hier direkt vor mir das Buch von 2003 liegen, das DDD überhaupt erst bekannt machte, da gibt es diese Warnung vor "zu viel" Service-Layer:
Eric Evans hat gesagt.:
Now, the more common mistake is to give up too easily on fitting the behavior into an appropriate object, gradually slipping toward procedural programming.
Hier ein Blog-Eintrag von 2003 dazu, das Zitat findest du dort auch: https://martinfowler.com/bliki/AnemicDomainModel.html

Beide deine genannten Aussagen haben allerdings Recht: Ja, nicht jedes Verhalten lässt sich in Domänen-Objekte pressen, deshalb gibt es (möglichst dünne) Service-Layer. Und ja: je mehr da drin ist (und je mehr es damit PP ähnelt), desto mehr macht man sich den Entwurf kaputt.
Ich würde drauf wetten, dass diese Abwägung auch sowohl in dem Tutorial von '09 als auch in dem Buch von '13 vorkommt.

Zur anderen Frage: Es wurden vor Jahren die verschiedenen Aufrufe der print-Methode in Büchern als Beispiel für Polymorphie genannt, obwohl es dabei ja eher um Overloading geht.

Darum halte ich eben für wichtig, abzuklären, was die Poster mit den Begriffen meinen, die sie verwenden.
Ja, manchmal wird Überladen auch als Polymorphie bezeichnet, aber üblicherweise meint Polymorphie, dass ein Typ verschiedene Ausprägungen hat (oder bei Messages: auf eine Message wird unterschiedlich reagiert.)
In dynamischen Sprachen (von denen Kays Definitionen kommen) gibt es auch überhaupt kein Überladen, weil es keine statischen Typen gibt. Und Messages die unterschiedliche viele Objekte entgegen nehmen, sind unterschiedliche Messages, nicht die gleiche in Überladen.


Aufrufe der print-Methode in Büchern als Beispiel für Polymorphie
Die print-Methode stammt aus einem Interface und hat zig Implementierungen, damit ist sie auch der üblichen Definition nach Polymorph ;)
 

knotenpunkt

Mitglied
Hey,

So da das Thema jetzt solangsam vom Komplexen in die Anarchie abzurutschen scheint,
greife ich mir einfach ein paar Punkte heraus. Andere werde ich ggf irgendwann später nachbearbeiten^^


@mrBrown
Du weichst in deiner Argumentation meinen Fragen/Aussagen aus, Indinzien dafür sind Begriffe wie Unsinn, oder die Bezugnahme zu einem ganz anderen Thema und .....

Irgendeinen Prozederuralen Code dahin klatschen und den zu OO umformen geht immer schief.
Liefer passenden Kontext dazu, dann liefer ich dir den passenden Code ;)

Wenn das interne Daten eines Objekts sind, ist da durchaus auch mal ein Switch valide, u.U. fährt man aber schon da mit Command-Objekten besser.
Das ist nicht einfach irgend ein prozeduraler Code, sondern ein häufig wiederkehrbares Pattern
An einem objektorientieren po don (ka wie der Begriff heisst^^)bzw. auf gut deutsch Analogum wäre ich sehr interessiert.



Ein Motorrad, welches die Innentemperatur der Sonne kennt, zeigt vor allem, dass man, um sein Argument zu unterstützen, die absurdesten Dinge konstruiert
Ich stüze kein Argument damit, sondern das ist einfach ein sich gut bildlich vorstellbarer User-Case^^
Und sollte OO das A und O sein, dann sollte es für OO kein Problem darstellen jeglichen Use-Case sinnvoll in OO-Code umzuwandeln.

Schlechte (also richtig beschissen und absolut unbrauchbarer) Entwurf: Motoradmotor braucht Sonneninnentemperatur
Besserer Entwurf: Motoradmotor braucht Umgebungstemperatur, welche die Umgebung hat. Wie die berechnet wird, und ob es Überhaut eine Sonne gibt (Meine Motorräder fahren nämlich nur in anderen Galaxien, in denen es entweder keine oder sieben Sonnen gibt), interessiert den Motor nicht sondern weiß die Umgebung.
Entwurf !=Anforderung bzw. angefragter Use-Case

Ja in meinem Fall besteht eine hohe Kopplung zwischen der Sonne und des Motorradmotors.
Ohne die Sonne könnte mein Motorradmotor nicht funktionieren.
Wie ich die ganze Sache bezüglich der Sonne noch flexibler machen könnte, indem ich die Anforderung als Optional markiere.
Sprich bei Existenz einer Sonne hat diese für des Motoradmotors eine Rolle zu spielen.
(Da ich Flexibilität liebe, wird es diese Zusatz-Anforderung bei mir sicherlich geben^^)
Aber anyway, die Anforderungen sind nun mal so und jetzt wäre ich an einem guten Design interessiert.

Ich bin ein ziemlich naiver programmiere, sehe also diese beiden mem_variablen und änder sie einfach, wie ich das grad brauche. Von der Wächtermethode weiß ich nichts, die ist ja irgendwo völlig anders.
Mein etwas weniger naiver Kollege will die Variablen nicht direkt nutzen, sondern denkt sich "ah, um die zu schützen braucht ich eine Wächtermethode" und schreibt sich einfach eine passende. Natürlich eine völlig andere, weil er deine Wächtermethode nicht kennt.
Die mem_variablen sind aber Unternehmensrelevant und dürfen nicht getrennt geändert werden. Dummerweise weiß ich das nicht und änder sie beliebig und mein Kollege ändert sie leider falsch.

Klingt sinnvoll, oder?

Die mem variablen liegen meintwegen hinter einem Fence und können tatsächlich nur über diese Wächterprozeduren geändert werden.
Die alleinige Existenz des Fence macht die Sache aber deshalb nicht objektorientiert
Dazu später mehr wenn ich die aufgeteilten Algorithmen näher erklären werde.
Apropo aufgeteilter Algorithmus:
Durch diesen Fence und den Wächterprozeduren habe ich schon einen kleinen aufgeteilten Algorithmus, da es nicht in der Verantwortung des Clients liegt, auf den Wertebereich der hinter dem Fence liegenden mem_Variablen aufzupassen. Diese Verantwortung liegt in den Wächterprozeduren.
Das geht schon teilweise Richtung Objektorientierung. Und es zeigt auch schon hier die damit zusammenhängend auftreten werdenden Nebeneffekte:
Flexibilitätseinbußen!
Ich kann so als Client den mem_variablen nicht mehr alle Werte geben, die ich diesen gerne geben würde, dies schränkt mich ein -> ich werde unflexibler
Klar je mehr Sicherheits/Kapselung ich bekomme desto weniger Rechte/Flexibiltäten stehen mir zu^^
Und das ist erst der Anfang vom Untergang^^



und das jetzt bitte in der prozeduralen Sprache Pascal.
Du weichst meiner Aussage/Fragestellung aus.


Dann nimm ne Sprache, in der sowas inlined wird, und es nur noch ein direkter Speicherzugriff ist. (Um's dir leichter zu machen: bist sogar schon auf der passenden Seite dafür ;) )
Und ja, genau so sieht Delegation aus.
ja mag sein dass der Optimierer das inlined. Und selbst wenn mir die IDE ein Tooling dafür anbietet, habe ich als Programmierer immer noch Mehraufwand^^


Wenn(!) die internen Daten relevant für außen sind, doch, dann ist es sinnvoll, für diese eine Schnittstelle zu bieten.
Um mal ein reales Beispiel zu geben Üblicherweise hab ich auch keinen direkten Zugriff auf dein Portmonee und kann mir einfach Geld rausnehmen, sondern frage dich, wenn du mir Geld geben sollst.
Und dann möchte ich irgendwann Taschendiebe einführen^^

Wenn nötig kann man durchaus zirkuläre Referenzen nutzen - im Idealfall aber nur als Laufzeit und nicht Kompilezeit-Abhängigkeit. In den meisten Fällen kann man es aber vermeiden.

Mach mal ein Beispiel für ne zirkuläre Abhängigkeit, die nur zur Laufzeit besteht

Und wie kommst du prozedural an die Bank?
Der Nutzer hat nur den Banknamen eingetippt, wird das in deinem Programm magisch zur Bank?
In OO wäre das einfach ein bankRepo.getBankByName(name) - ein Interface. welches für genau den Zweck da ist.
Aber spaßeshalber einfach mal von der echten Welt ableiten: Huch, sieht ja da wie in der OO Variante aus. Bestimmt total unhilfreich für jeden Domänenexperten, wenn das Programm die Domäne eins-zu-eins abbildet....
Falls das BankRepo nicht weiter konfiguriert ist, dann ist es eine anemic Service-Klasse, dessen Methoden auch ganz einfach via call func aufgerufen werden könnten, also prozedural


Für dich ist also "3 Variablen im Speicher ablegen und eine Funktion aufrufen" deutlich unflexibler als "3 Variablen im Speicher ablegen und eine Funktion aufrufen"? Kann man so sehen, ist aber etwas merkwürdig...
Nein die Flexibiltät ist in dem Fall bei beiden gleich!
Nur dass ich es schaffe, dass diese gleich ist, muss speicher to heap call -> call method -> call gc machen
Und das ist ein teures Unterfangen. Und ich glaube nicht, dass das nacher ein zu eins gleich schnell und ressourcenschonend abläuft - troz guter Optimierer.
Und das macht bei N-> Große Zahl dann schon ein Unterschied.
Und weil es der gleiche Code nur anders syntaktisch ausgedrückt ist, würde ich hier den prozeduralen Stil bevorzugen. Zumal der Code mit new Object()->call_method->destruct eben objektorientierte Syntax hat, aber eigentlich kein objektorientierter Code ist!

Nö, kann ich nicht, weil es Unsinn ist. Siehe den Punkt hier drüber.
Ganz generell, du befürwortest solche ActionObjects?
Diese sind für mich klar prozedural!
Der Unterschied ist nur etwas mehr Code-Schreibarbeit und etwas unperformanter



Das ist der Unterschied zwischen Dependeny Injection und dem großen Haufen Code, ersteres hat sich nicht ohne Grund durchgesetzt ;)
Wie sieht für dich DI aus?
Du würdest ein dynamisch zur Laufzeit gesuchtes Item Objekt irgendwo hineininjecten?

DI sehe ich eigentlich eher im Zusammenhang von Konfigurationsdaten into Service-Objekte
und Serviceobjekte into other Serviceobjekte

Zumal man zwischen DI und Strategy-Pattern unterschieden sollte. (auch wenn es genau genommen das gleiche tut^^)
DI wird eher einmalig zur Startzeit des Objekts eingesetzt, das Strategy-Pattern dann zur lifetime des objekts, was immer mal wieder eine neue Strategie bekommt^^
Aber der Absatz sollte nur informieren und tut jetzt nichts weiter zur Sache^^


Glückwunsch, du hast erkannt, dass deklarative Sprachen oft toller sind als Prozedurale Sprachen :) Gehe ich vollkommen konform mit ;)
Da stimme ich dir zu. Declarative Sprachen machen echt Spaß^^


Da ich später noch ein Bluetooth-Kommunikationsmodul, über das die gleiche Funktionalität verfügbar ist, hinzufügen möchte, beschränken sich die Kommunikationsmodule nur auf den Kommunikationsteil, ist doch völlig logisch?

Und das macht die Programme heute so langweilig, weil jeder nur noch sein eigenes Süppchen kocht.
Ich möchte eben mein das andere Kommunikationsmodul eng binden. Ich möchte die Einschaltvorgänge meiner Lichtanlage davon abhängig machen wielange die aktuellen PING-Zeiten des Clients sind, das ist einfach so^^

Aber auch in diesem Fall würde ich versuchen das ganze so flexibel zu machen, um nur im Falle der Kommunikation über eben dieses Kommunikationsmoduls davon abhängig zu sein.

Wenn ich dann über Bluetooth kommuniziere, sind mir die PING-Zeiten egal.
Vllt. möchte ich aber auch etwas bluetooth-spefzisches dann haben???!!!!!!^^

Wie genau würdest du ein derartiges System designen?


Oder: der Algorithmus, wie du ihn dort aufgeschrieben hast, ist zu kompliziert.
Einfach mal vernünftig modellieren, dann kann man damit vielleicht was anfangen ;)

Das sind Anforderungen, modelliert wird doch erst jetzt^^

Ich hab keine Ahnung von der Domäne, deshalb kann ich nur "vielleicht, vielleicht auch nicht" sagen...
Wie schon mal gesagt: völlig Ahnungslos vollkommen kontextlose Dinge zu modellieren geht immer schief, und in dem Fall hab ich weder Ahnung noch Kontext.
Generell gibts aber durchaus sowas wie Context and Dependency Injection, ist oftmals ganz hilfreich bei sowas...
Wie und wo setzt du DI ein? Das würde mich mal ganz allgemein interessieren^^

Ganz im Gegenteil: meistens funktioniert das wunderbar. Macht man btw auch in prozeduraler Programmierung (ich weiß, ist schwer zu glauben, aber die meisten Programme haben mehr als eine Prozedur).
Nur weil ich mehrere prozeduren verwende, ist der Algorithmus noch nicht unbedingt so richtig dezentralisiert.
Ich verwende mehrere Prozeduren der Übersichtbarkeit wegen. Diese sind jedoch eng miteinander verwoben und untereinander hochgradig abhängig. Also solange ich mich im Kontext eines Features befinde. Damit meine ich dann die Modulinternen Grenzen.


Joa, üblicherweise brauche ich Objekte, wenn ich sie ändern will. Finde ich jetzt auch nicht sehr störend.
Wenn ich irgendein Objekt gar nicht haben will, will ich es auch üblicherweise nicht verändern (ich find es schon ganz geil, dass meine Kaffeemaschine nicht plötzlich die Sonneninnentemperatur ändert...)
Und die ganze Abghänigkeiten dazu auch.
Wenn ich nur die Sonneninnentemperatur wissen möchte, brauche ich nur die Sonneninntentemperatur, nicht aber die ganze Sonne, oder im Zweifel auch noch das Weltall dazu.

Und ich fände es schon ganz witzig, wenn mein zu 2/3 gefüllter Kaffeebecher unseren Mond zum explodieren bringen könnte^^
Deine Welt ist unflexibel, starr, sicher und langweilig
Meine ist flexibel, elastisch, (fehleranfällig) und macht Spaß^^

Das Fehleranfällig muss nicht sein, wenn man sich an ein paar Regeln hält^^


Stichwort: sinnvolle Modellierung. Wenn man nicht zusammengehörende Daten beliebig zusammenfasst, bekommt man *immer* Probleme - völlig unabhängig welches Konzept und welche Sprache und sogar in der realen Welt.

"sobald ich [ganz prozedural viele Variablen in einem Struct] zusammenfasse und [Prozeduren, die dieses Nutzen] definiere, so ist die [Prozeduren] immer abhängig von ALLEN [Variablen des Structs], auch wenn nicht alle benötigt werden."

Nur dass ich aus nem Struct auch mal schnell nen Sub-Struct bauen kann und einer Methode dann genau die Daten zur Verfügung stellen kann, die diese ausschließlich braucht.

Wie gesagt: der Punkt an sich ist schon völliger Unsinn.
Warum?
Entweder du heisst die flexiblen ActionObjekte gut?
Oder du verwendest normale Objekte, die aber gemäß der THIS-Daten unflexibler werden.
Siehe dazu das Beispiel aus meinem letzten Beitrag

Ich habe keine Ahnung, was du plötzlich zu verteilten Algorithmen meinst und wie du dazu kommst und was diese mit dem Thema zu tun haben, deshalb ignorier ich's einfach mal...
ich glaube verteilte Algorithmen sind das was die OO ausmacht.

Du hast nicht eine zentrale Instanz, die über all die Daten herrscht und einen Algorithmus ausführt, sondern du versucht diesen Algorithmus auf Objekte aufzuteilen.
So teilst du dem Kommunikationsobjekt entsprechenden Code zu und dem RelaisManager anderen Code

Nur das Problem was ich damit habe ist das, wenn ich jetzt die Kommunikationseinheit mit der Relaieinheit so sehr verweben möchte, dass ich den Code nicht mehr gut aufteilen kann, dann knallts.

Wie und wo würdest du den Code hinstecken, wenn mehrere Module ziemlich abhängig voneinander sind?

Services? etwas anderes?


Zum Thema Service und DI hätte noch folgendes anzumerken:


Hier ein Blog-Eintrag von 2003 dazu, das Zitat findest du dort auch: https://martinfowler.com/bliki/AnemicDomainModel.html

Beide deine genannten Aussagen haben allerdings Recht: Ja, nicht jedes Verhalten lässt sich in Domänen-Objekte pressen, deshalb gibt es (möglichst dünne) Service-Layer. Und ja: je mehr da drin ist (und je mehr es damit PP ähnelt), desto mehr macht man sich den Entwurf kaputt.
Ich würde drauf wetten, dass diese Abwägung auch sowohl in dem Tutorial von '09 als auch in dem Buch von '13 vorkommt.


ich bin der Meinung, dass es gar keine Services geben darf, wenn man richtig OO programmiert.
Warum Martin Fowler das Konzept selbst etwas aufweicht, habe ich auch schon vor ca. 3 Jahren nicht verstanden.

https://www.php.de/forum/webentwick...-procedural-programming?p=1449839#post1449839

In diesem Faden habe ich auch noch ein paar andere Problematiken von OO bearbeitet.


Soweit mal wieder^^


lg knotenpunkt
 

AndiE

Top Contributor
@knotenpunkt : So richtig erschließt sich mir deine Position nicht. Im Bereich der DDD teile ich nach den Autoren den Use-Case in seine Einzelschritte und lege dazu Packages an.

Ein Kunde bestellt mehrere Positionen. Der Kunde wird aus der Kundendatei herausgesucht. Dann werden die bestellten Dinge in einem Lieferschein zusammengefaßt. Mit Erstellung des Lieferscheines wird eine Rechnung erstellt.

Im Sinne von DDD wäre die Kundenerfassung ein Baustein, die Erstellung des Lieferscheins der zweite und die Rechnungserstellung der dritte.

Wenn ich das objektbezogen plane habe ich neben der Anwendungsklasse eine Kundenverwaltungsklasse, die die Kunden verwaltet, eine Klasse für die Verwaltung der Lieferscheine, der Produkte und eine Klasse für die Rechnungen. Im allgemeinen habe ich noch eine Money-Klasse, die die Geldbeträge verwaltet.

Man kann hier sehen, dass bei der DDD die Verwaltung der Produkte noch nicht als Baustein geplant wurde, was ich ergänzen kann. Und so kann ich auch andere Veränderungen im Use-Case oder in der Modellierung ergänzen oder verändern.

ich würde sagen, die Dinge sind in beiden Fällen recht gut getrennt. Das halte ich auch für wichtig, weil ich so Bausteine und Klassen jeweils für sich alleine testen kann. Und die Schnittstellen sind auch recht eindeutig fassbar
 

mrBrown

Super-Moderator
Mitarbeiter
@mrBrown
Du weichst in deiner Argumentation meinen Fragen/Aussagen aus, Indinzien dafür sind Begriffe wie Unsinn, oder die Bezugnahme zu einem ganz anderen Thema und .....
Nur weil ich Unsinn auch so bezeichne, weich ich noch lange nicht aus :p
Wo hab ich denn Bezug auf ein ganze anderes Thema genommen?

Das ist nicht einfach irgend ein prozeduraler Code, sondern ein häufig wiederkehrbares Pattern
An einem objektorientieren po don (ka wie der Begriff heisst^^)bzw. auf gut deutsch Analogum wäre ich sehr interessiert.
Man bekommt keinen OO-Code, wenn man beliebigen Code nimmt, und diesen umformt.

Wesentlich für OO-Design ist der Modellierungsprozess - und den hat man nicht, wenn man Prozeduralen Code ohne Kontext bekommt und umformen soll.

Ich stüze kein Argument damit, sondern das ist einfach ein sich gut bildlich vorstellbarer User-Case^^
Und sollte OO das A und O sein, dann sollte es für OO kein Problem darstellen jeglichen Use-Case sinnvoll in OO-Code umzuwandeln.
Wie schon gesagt: das A und O für alles gibt es nicht ;) Wenn in einem System alles alles kennen muss, es also absolut keine Kapselung geben darf, ist OO falsch.

Ich kann mir aber auch nur sehr schwer bildlich einen Motoradmotor vorstellen, der die Sonneninnentemperatur kennt...

Aber anyway, die Anforderungen sind nun mal so und jetzt wäre ich an einem guten Design interessiert.
Wenn die Anforderung das völlige fehlen jeglicher Kapselung ist, dann ist ein Paradigma, bei dem Kapselung eines der Hauptprinzipen ist, falsch. Da geb ich dir völlig Recht, für diesen Anwendungsfall gibt es keine OO-Lösung.


Klar je mehr Sicherheits/Kapselung ich bekomme desto weniger Rechte/Flexibiltäten stehen mir zu^^
Und das ist erst der Anfang vom Untergang^^
Für mich ist das das Ende der Katastrophe...kommt auf die Sichtweise an ;)

Du weichst meiner Aussage/Fragestellung aus.
Nö. Ich zeige dir nur, dass deine Erwartungen an Prozedurale Sprachen nur Erwartungen an konkrete prozedurale Sprachen sind, aber nichts mit dem Paradigma zu tun haben.

Die Nachteile, die du dort für OOP aufgezählt hast, sind keine Nachteile von OOP, sondern von einzelnen Sprachen, sowohl OOP als auch PP als auch allen anderen!

Und dann möchte ich irgendwann Taschendiebe einführen^^
Kannst du machen. Aber auch wenn es Taschendiebe gibt, sogar einen, der direkt neben dir steht, habe trotzdem nicht ich von dem Rechner, an dem ich grad sitze, Zugriff auf die Münzen im Bargeldfach deines Portmonees.

Mach mal ein Beispiel für ne zirkuläre Abhängigkeit, die nur zur Laufzeit besteht
Compilezeit:
Klasse A hat eine Abhängigkeit von Interface b.
Klasse B implementiert Interface b und hat eine Abhängigkeit zu A.
A hat aber keine zu B!
Laufzeit:
A wird ein Objekt von B übergeben.
A kennt B, B kennt A.

Falls das BankRepo nicht weiter konfiguriert ist, dann ist es eine anemic Service-Klasse, dessen Methoden auch ganz einfach via call func aufgerufen werden könnten, also prozedural
Von dem Interface gibt es 42 verschiedene Implementierungen, die intern beliebig aufgebaut sein können.
Schon ist's nicht mehr einfach über Prozeduren abbildbar.

Nur dass ich es schaffe, dass diese gleich ist, muss speicher to heap call -> call method -> call gc machen
Der Aufbau des Speichers hängt nicht vom Paradigma ab!
Auf den Rest geh ich deshalb gar nicht erst ein.

Ganz generell, du befürwortest solche ActionObjects?
Diese sind für mich klar prozedural!
Der Unterschied ist nur etwas mehr Code-Schreibarbeit und etwas unperformanter
Ja, in Anwendungsfällen, in denen sie sinnvoll sind, befürworte ich sie.
Nein, sie sind nicht prozedural.
Sie sind eben Daten+Funktion, und nicht einfach nur irgendeine Prozedur.

Wie sieht für dich DI aus?
Du würdest ein dynamisch zur Laufzeit gesuchtes Item Objekt irgendwo hineininjecten?

DI sehe ich eigentlich eher im Zusammenhang von Konfigurationsdaten into Service-Objekte
und Serviceobjekte into other Serviceobjekte
Es ist ein weit verbreitetes Missverständnis, dass DI "dynamisch zur Laufzeit gesuchte Objekte" oder "Service-Objekte" bedeuten würde.
Es ist völlig egal, was für eine Abhängigkeit und wie diese übergeben wird - es muss nur eine Abhängigkeit sein, die übergeben wird.

Zumal man zwischen DI und Strategy-Pattern unterschieden sollte. (auch wenn es genau genommen das gleiche tut^^)
Nein, die tun nicht das gleiche. Für das Strategy-Pattern nutzt man üblicherweise DI, DI setzt aber keineswegs eine Strategie voraus, die injiziert wird.
Das sind Anforderungen, modelliert wird doch erst jetzt^^
Wenn irgendwo ein von einzelnen Softwaremodulen inklusive deren Arbeitsweise die Rede ist, wurde schon modelliert, sonst wäre das Modul und deren Arbeitsweise nicht da ^^

Wie und wo setzt du DI ein? Das würde mich mal ganz allgemein interessieren^^
Immer, wenn ein Objekt besser außerhalb dessen, was es benutzt, erzeugt werden kann.
Das sind natürlich alle Services, aber eben auch ganz normale Objekte.

Deine Welt ist unflexibel, starr, sicher und langweilig
Meine ist flexibel, elastisch, (fehleranfällig) und macht Spaß^^
Nur so aus Interesse, aber hast du jemals ein größeres OO-Projekt umgesetzt?

Nur das Problem was ich damit habe ist das, wenn ich jetzt die Kommunikationseinheit mit der Relaieinheit so sehr verweben möchte, dass ich den Code nicht mehr gut aufteilen kann, dann knallts.
Wenn ich bei meinem Haus den Dachboden im 3. Stock und den Keller stark verweben möchte, knallt's auch (bzw bricht zusammen). So ist das halt, wenn man zwanghaft völlig getrennte Dinge zusammenbringen möchte...

Wie und wo würdest du den Code hinstecken, wenn mehrere Module ziemlich abhängig voneinander sind?
Wenn sie so stark verwoben sind, sind es keine unterschiedlichen Module.
Wenn irgendwer sie als unterschiedliche Module modelliert hat, hat der in dem Fall Mist gebaut.



ich bin der Meinung, dass es gar keine Services geben darf, wenn man richtig OO programmiert.
Warum Martin Fowler das Konzept selbst etwas aufweicht, habe ich auch schon vor ca. 3 Jahren nicht verstanden.
*DU* bist der Meinung. Begründen kannst du die aber nur mit "ganz oder gar nicht".
Analoges Beispiel: Im Straßenverkehr passieren Unfälle.
Die eine Reaktion darauf wäre zu einem Optimum hin arbeiten, z.B. mit möglichst sicheren Autos und StVO (OOP mit Service-Klassen)
Eine andere wäre, StVO und alle Sicherheitseinrichtungen aus Autos abzuschaffen ("weil OOP nicht 100% deinem OOP-Verständnis entspricht kein OOP nutzen)


https://www.php.de/forum/webentwick...-procedural-programming?p=1449839#post1449839

In diesem Faden habe ich auch noch ein paar andere Problematiken von OO bearbeitet.
Da steht das gleiche in grün^^
 

knotenpunkt

Mitglied
Hey,

Man bekommt keinen OO-Code, wenn man beliebigen Code nimmt, und diesen umformt.

Wesentlich für OO-Design ist der Modellierungsprozess - und den hat man nicht, wenn man Prozeduralen Code ohne Kontext bekommt und umformen soll.
Ich habe eine Funktionalität, die ich realisieren möchte. Diese kann ich mit OO oder PP realisieren. Von daher müsste beides ineinander umformbar sein. Falls nicht, zeigt es doch eindeutig, dass OO stark einschränkend ist, oder aber eine verkomplizierte und nicht ressourcenschonende Programmierung vorraussetzt.
(siehe BSP diese ActionObjects, zumal ich von denen sowieso behaupten würde, dass diese Prozedural sind, nur eben mit ein paar Keywörtern aus der Objektorientierung)



Wie schon gesagt: das A und O für alles gibt es nicht ;) Wenn in einem System alles alles kennen muss, es also absolut keine Kapselung geben darf, ist OO falsch.

Ich kann mir aber auch nur sehr schwer bildlich einen Motoradmotor vorstellen, der die Sonneninnentemperatur kennt...
Nein es muss nicht alles alles kennen. Aber zumindest Modulintern wäre das ziemlich schön.
Gehen wir davon aus unser Sonnensystem ist nur ein kleines Modul ist, in einem System das viel Größer ist.

Modul != Klasse (zumindest sollte es so sein?!)

Und das ist das Problem: Jede klasse ist in sich genommen ein eigenes abgeschottetes Modul.
Deiner Aussage zu Folge dürfen zwei Klassen so gut wie nichts von einander wissen.
Falls doch, wäre es toll, wenn du dahingehend deine Argumentation nochmal neu aufrollen würdest^^


Wenn die Anforderung das völlige fehlen jeglicher Kapselung ist, dann ist ein Paradigma, bei dem Kapselung eines der Hauptprinzipen ist, falsch. Da geb ich dir völlig Recht, für diesen Anwendungsfall gibt es keine OO-Lösung.
Also ist OO überall da falsch, wo ich Dinge/Funktionalität auf mindestens zwei Klassen aufteilen muss?
Diese aber voneinander wissen müssen, damit das Gesamtkonzept funktioniert?
Also sprich ist OO immer falsch?!^^

Für mich ist das das Ende der Katastrophe...kommt auf die Sichtweise an ;)
ja^^ (das ja ist jetzt keine Zustimmung^^)

Kannst du machen. Aber auch wenn es Taschendiebe gibt, sogar einen, der direkt neben dir steht, habe trotzdem nicht ich von dem Rechner, an dem ich grad sitze, Zugriff auf die Münzen im Bargeldfach deines Portmonees.
Etwas mehr Kreativität. Die Welt so wie sie ist, ist doch langweilig, in meiner erfundenen Welt ginge das beispielsweise^^
Klar wenn ich jetzt irgendwas aus der uns bekannten Welt abbilden möchte, da ginge das nicht. Aber sobald du eben ein Computerspiel oder Sonstiges entwirfst, da sollten dir keine Grenzen gesetzt sein und schon gar nicht von einem Programmierparadigma. Die Gesetzmäßigkeiten in dem Programm gibst du selbst vor und sollten dir nicht von dem Programmierparadigma vorgegeben werden.


Von dem Interface gibt es 42 verschiedene Implementierungen, die intern beliebig aufgebaut sein können.
Schon ist's nicht mehr einfach über Prozeduren abbildbar.
Und das ist noch ein weiterer schlechter Beigeschmack seitens OO. Warum sollte ich 42 verschiedenartige Implementierungen machen wollen?
Das macht nur dann Sinn, wenn ich ne Bibliotheksfunktion/Modul entwerfe, und diese auf unterschiedliche Aspekte ausrichte. Bspw. ne QUEUE, die ich einmal so implementiere und ein ander mal so. Bei suchlastiger Benutzung ist eventuell QUEUE Implementierung 1 besser wie 2, welches da bei einfacher Speicherung besser performt.
Aber im allgemeinen verstehe ich es nicht, warum man 42 verschiedene Typen entwerfen sollte.

ABER das ist auch der einzige vorteil, wenn da class BankRepo steht statt nen einfachen Call wie give_me_Bank(id, sonstiges);

btw. wäre auch das noch möglich give_me_bank(id, implementierungs_ID, sonstiges); ^^


Der Aufbau des Speichers hängt nicht vom Paradigma ab!
Auf den Rest geh ich deshalb gar nicht erst ein.
Ja da hast du recht^^.
also ich würde sagen call_func1(parameter); und tmp=new Func1_Object(parameter); tmp->action(); //gc tmp
sind beides prozedurale Realisierungen. Nur das zweiteres eben Keywörter aus der objektorientierung verwendet, das ganze ressourcenfressender/langsamer ist und mir keine weiteren Vorteile einräumt.
Warum sollte ich dann Zweiteres verwenden?
Warum sollte ich allgemein irgendwas davon verwenden, wenn ich OO programmieren möchte?
Wie gesagt es sind beide Realisierungen prozedural.

Ja, in Anwendungsfällen, in denen sie sinnvoll sind, befürworte ich sie.
Nein, sie sind nicht prozedural.
Sie sind eben Daten+Funktion, und nicht einfach nur irgendeine Prozedur.
Du hast ja oben selbst geschrieben, dass man PP nicht so einfach in OO umwandeln kann.
Hier geht es, aber es geht auch nur, weil der scheinbare oo-code weiterhin prozedural ist.


Es ist ein weit verbreitetes Missverständnis, dass DI "dynamisch zur Laufzeit gesuchte Objekte" oder "Service-Objekte" bedeuten würde.
Es ist völlig egal, was für eine Abhängigkeit und wie diese übergeben wird - es muss nur eine Abhängigkeit sein, die übergeben wird.
Könntest du DI etwas weiter ausführen, wie du es einsetzt. vllt. auch ein/zwei/gar 3? gute Codebeispiel(e)^^, was/welche mich somit dann schon eher von OO überzeugen könnte^^

Wenn irgendwo ein von einzelnen Softwaremodulen inklusive deren Arbeitsweise die Rede ist, wurde schon modelliert, sonst wäre das Modul und deren Arbeitsweise nicht da ^^
hmmm, ok^^

Wenn ich bei meinem Haus den Dachboden im 3. Stock und den Keller stark verweben möchte, knallt's auch (bzw bricht zusammen). So ist das halt, wenn man zwanghaft völlig getrennte Dinge zusammenbringen möchte...
Hier muss man einfach die Kreativität wieder einschalten, dann geht das schon^^

Wenn sie so stark verwoben sind, sind es keine unterschiedlichen Module.
Wenn irgendwer sie als unterschiedliche Module modelliert hat, hat der in dem Fall Mist gebaut.
Ja hier sind wir wieder bei der Thematik. ob Klasse == Modul oder Klasse != Modul

Wie trennst du Module?
Wie soll ich mein Motoorradmotor mit der Sonneninnentemperatur verknüpfen, wenn beides in gleichem Modul liegt und ich das ganze OO gestalten möchte?

*DU* bist der Meinung. Begründen kannst du die aber nur mit "ganz oder gar nicht".
Analoges Beispiel: Im Straßenverkehr passieren Unfälle.
Die eine Reaktion darauf wäre zu einem Optimum hin arbeiten, z.B. mit möglichst sicheren Autos und StVO (OOP mit Service-Klassen)
Eine andere wäre, StVO und alle Sicherheitseinrichtungen aus Autos abzuschaffen ("weil OOP nicht 100% deinem OOP-Verständnis entspricht kein OOP nutzen)
also ich finde schon, dass man entweder 100%iges OO programmieren sollte, oder gar nicht.
Zumindest aber müsste es ja möglich sein 100%iges OO einschränkungslos programmieren zu können?, wenn es das Paradigma der heutigen Wahl ist?!^^



Da steht das gleiche in grün^^
Auch wenn es in rot dastünde, wäre es das gleiche...... zumindest für mich^^ Da ich die Farben nicht so genau auseinanderhalten kann^^
Naja ganz das gleiche steht da nicht, ein paar weitere Aspekte habe ich dort schon auch noch erwähnt, aber war vor ca. 3 Jahren, manches würde ich vllt. gar nicht mehr so unterstreichen.....


Jetzt habe ich mal wieder ein praktisches Beispiel:


Gehen wir mal davon aus ich baue einen Chat,

Irgendwo habe ich ein Modul, das sich um die Netzwerkkommunikation kümmert.
Am besten eines, das ein nicht blockierendes reactive Modul, wie Netty nutzt (aber das ist nur nebensächlich).


Der Chat hat jetzt mehrere Chaträume und diese Räume können Unterräume haben (übrigens soll alles dynamisch aufgebaut werden: Die Raumstruktur ist also nicht fix)


****** Das hier als kleine Zusatzanforderung, die jetzt aber nicht Hauptkriterium meiner Frage ist*******

Sollte ein Raum länger unbesucht sein, wird er nicht im Arbeitsspeicher gehalten, sondern soll in der Datenbank verweilen.

Im Falle des Betretens kann er in das Serverprogramm geladen werden. Im Falle der Abfrage von Rauminformationen von Aussen, wo nicht erwartet wird, dass viel mehr mit dem Raum interagiert wird, sollen gezielte Informationen ausschließlich aus der Datenbank geholt werden, ohne dass der Raum in seiner Vollständigkeit in den Server geladen werden muss (performance-Gründe!)
Ich gehe mal davon aus, mittels des Proxypattern zu realisieren???!!!

***************************Ende******************************************************


In den einzelnen Chaträumen können Befehle ausgeführt werden, oder auch nicht ausgeführt werden, je nach Raumtyp und Raumkonfiguration gibt es diverse Befehle oder gibt es nicht.

So jetzt wird das ganze interessant

Je nach Befehlstyp, Raumtyp/config.... Usertyp, vorherige Netwerkbelastung des Users, andere Modulzustände etc pp verhält sich entsprechender Befehl anders.

Beispiele (Wir haben den Raum X)

Der User hat einen globalen Mute -> er wird keine Chatnachricht in Raum X absenden können.
oder vllt doch?. Vllt gibt es Räume die den globalen Mute ignorieren, oder einen noch verschärfteren Globalen Mute vorrraussetzen, dass der User nicht schreiben kann!

Ein Admin, der sich nicht in Raum X befindet, kann auch von Aussen in den Raum schreiben
Alle anderen User müssen sich innerhalb des Raumes X befinden um schreiben zu können.
Ausgenommen sind Speziallräume, die von auch von Moderatoren von Aussen beschrieben/gelesen werden können


In Raum X können User, die mit der IP-Adresse ???. anfangen nur alle 10min eine Nachricht hinterlassen.


Dem Admin stehen in Raum X viele weitere Befehle zur Verfügung


usw usf.


Bei einer Nachricht im Raum X, werden alle sich im raum befindlichen notified
Ein Admin, der in den letzten 10min von Aussen in den Raum geschrieben hat, wird auch benachrichtigt
Sollte Raum X entsprechend konfiguriert sein, werden alle im Raum befindlichen User, die in den letzten 15min nichts geschrieben haben, auch nicht benachrichtigt, oder weil meiner Kreativität keine Grenzen gesetzt sind: Werden diese doch benachrichtigt. Der Chattext soll aber durchgewürfelt bei Ihnen ankommen.


Ausserdem kann es sein, wenn die Räume verschachtelt exisitieren, dass parentRoom, seine Config an tiefer liegenden Raum weitergibt

Wie würdet ihr das objektorientiert umsetzen?



Prozedural ist das relativ einfach (auch wenn jetzt nur kurz shemenhaft angerissen und nicht alle constraints beachtet):



commandData=.....;
welcherRaum=commandData.raum
rconfig=getRaumConfig(welcherRaum);
if(rconfig.isAviableCommand(commandBlob)){abbort;}
switch(command)
{
commandBlob:

ip=....
userRight=......//lese aus der DB herauz welche Rechte der User hat
//.....

if(/*hier wird alles mögliche geprüft*/)

//hier werden die daten zubereitet

//und hier potentielle empfänger benachrichtigt und Nachrichten in Structs/Buffer/Datenbank eingetragen
//Also für Logging, oder im Falle dessen dass eine Nachricht nicht zugestellt werden kann, zum Neusenden

//usw
//..
}


Die Frage bei der objektorientierung ist, wie würdet ihr das ganze aufteilen, wo würde der Code stehen?
Entweder ich baue nen Manager aussen, ein Service der sich alle relevanten Daten holt und diese setzt und weitereicht(notify von den clients)....... das ist aber für mich dann eigentlich sehr prozedural (siehe meinen skizzenhaften Code)
Oder ich schreibe den Code in die Raumklasse?, müsste da aber alles von aussen reinreichen, den ganzen Kontext? (Ausserdem habe ich dann Coderedundanz, da ich vermutlich ähnlichen Code in einem anderen Raumtyp wiederholend schreiben müsste)
Und für den Fall, dass Bspw der User in Raum Y bereits 7 Nachrichten geschrieben hat, so darf er in Raum X gerade keine mehr schreiben, also auch an die Information muss ich irgendwie kommen. Ein ausstehendender Manager tut sich da sicher einfacher, aber ist eben eher prozedural.
Oder ich teile den Code irgendwie auf verschieden Klassen auf, aber wie?



Jetzt bin ich mal auf eure Modellierungen gespannt^^




Nur so aus Interesse, aber hast du jemals ein größeres OO-Projekt umgesetzt?
Nein tatsächlich nicht, bin Informatik Student^^
An der Uni lernt man aber kein gutes Coding.

Also wenn du nichts dagegen hast, könnten wir auch mal skypen/discorden/teamspeaken etc pp.




soweit mal wieder


lg knotenpunkt
 

mrBrown

Super-Moderator
Mitarbeiter
Ich habe eine Funktionalität, die ich realisieren möchte.
Ich habe erstmal eine Problemstellung, die ich lösen möchte.
Das *wie* (die Funktionalität) gibt die erstmal nicht vor.
Aus der Modellierung des Problems ergibt sich dann die Umsetzung. Die kann OOP sein, die kann PP sein, die kann FP sein. Wenn man aber Funktionalität beliebig von einer Umsetzung in die anderen umformen kann, kommt Bullshit raus - eben weil der wesentliche Schritt, die Modellierung, fehlt.

Ich setz dich auch nicht vor Schloss Neuschwanstein und lass dich das zu einem Hochhaus umbauen.

Von daher müsste beides ineinander umformbar sein. Falls nicht, zeigt es doch eindeutig, dass OO stark einschränkend ist, oder aber eine verkomplizierte und nicht ressourcenschonende Programmierung vorraussetzt.
Alle Sprachen sind ineinander umformbar.
Du kannst das auch mit Powerpoint umsetzen, zeigt das jetzt, dass PP nicht besser ist als Powerpoint?

siehe BSP diese ActionObjects, zumal ich von denen sowieso behaupten würde, dass diese Prozedural sind, nur eben mit ein paar Keywörtern aus der Objektorientierung
Wenn du die Kombination aus Verhalten und Daten als Prozedural siehst, kannst du das gern machen. Wenn du aber zwischen OOP und PP keinen Unterschied siehst, ist diese Diskussion hier ziemlicher Unsinn...


Nein es muss nicht alles alles kennen. Aber zumindest Modulintern wäre das ziemlich schön.
Gehen wir davon aus unser Sonnensystem ist nur ein kleines Modul ist, in einem System das viel Größer ist.
Und in dem größerem System haben wir zwei vollkommen unabhängige Sonnensysteme. Die trotzdem vollen Zugriff aufeinander haben sollen?

Modul != Klasse (zumindest sollte es so sein?!)

Und das ist das Problem: Jede klasse ist in sich genommen ein eigenes abgeschottetes Modul.
Also Klassen sind keine Module aber Klassen sind Module? Du solltest dich schon für eine Sichtweise entscheiden, auch wenn beide Begründbar sind...

Analog.
Modul != Prozedur
Und das ist das Problem: Jede Prozedur ist in sich genommen ein eigenes abgeschottetes Modul.

Also ist OO überall da falsch, wo ich Dinge/Funktionalität auf mindestens zwei Klassen aufteilen muss?
Diese aber voneinander wissen müssen, damit das Gesamtkonzept funktioniert?
Also sprich ist OO immer falsch?!^^
Nein, OO ist falsch, wenn es *keinerlei* Kapselung geben soll und dir alles völlig egal ist.
(Und OO ist falsch, wenn man es nicht verstanden hat, für dich also immer ;) )

Etwas mehr Kreativität. Die Welt so wie sie ist, ist doch langweilig, in meiner erfundenen Welt ginge das beispielsweise^^
Klar wenn ich jetzt irgendwas aus der uns bekannten Welt abbilden möchte, da ginge das nicht. Aber sobald du eben ein Computerspiel oder Sonstiges entwirfst, da sollten dir keine Grenzen gesetzt sein und schon gar nicht von einem Programmierparadigma. Die Gesetzmäßigkeiten in dem Programm gibst du selbst vor und sollten dir nicht von dem Programmierparadigma vorgegeben werden.
Wenn das möglich ist, modellierst du das auch so, da steht dir OO überhaupt nicht im Wege...
Welche Computerspiele sind eigentlich noch rein Prozedural umgesetzt? ;)

Und das ist noch ein weiterer schlechter Beigeschmack seitens OO. Warum sollte ich 42 verschiedenartige Implementierungen machen wollen?
Weil es 42 verschiedene Implementierungsmöglichkeiten gibt? Hint: 42 steht da nur wegen 42.
Was übrigens auch Typen sind: Object, Compareable, Serializable, Cloneable, etc. Für die solltest du die 42 um ein paar Nullen ergänzen.

ABER das ist auch der einzige vorteil, wenn da class BankRepo steht statt nen einfachen Call wie give_me_Bank(id, sonstiges);

btw. wäre auch das noch möglich give_me_bank(id, implementierungs_ID, sonstiges); ^^
Was gibt denn give_me_bank eigentlich zurück?
Vielleicht ein Bank-Objekt?

das ganze ressourcenfressender/langsamer ist
NEIN! immer noch nicht. Das sage ich jetzt gefühlt in jedem Beitrag. Egal wie oft du es wiederholst, es wird nicht richtiger.

mir keine weiteren Vorteile einräumt.
Warum sollte ich dann Zweiteres verwenden?
Warum sollte ich allgemein irgendwas davon verwenden, wenn ich OO programmieren möchte?
Wie gesagt es sind beide Realisierungen prozedural.
Wer sagt, dass man das Objekt an der Stelle verwenden muss? Ist üblich, sowas im Programm rumzureichen.

Und wie gesagt, die eine Implementierung ist OO.

Könntest du DI etwas weiter ausführen, wie du es einsetzt. vllt. auch ein/zwei/gar 3? gute Codebeispiel(e)^^, was/welche mich somit dann schon eher von OO überzeugen könnte^^
Guck dir ein beliebiges Buch an, was sich mit OO beschäftigt. Können die besser erklären als ich (wird dich aber trotzdem nicht überzeugen^^)
Es ist auch ganz einfach: Immer, wenn du einem Objekt etwas übergibst, was es benötigt, ist es DI.
Jeder Konstruktor mit nicht primitiven Parametern ist DI.

Hier muss man einfach die Kreativität wieder einschalten, dann geht das schon^^
Wie gesagt: du kannst für alles irgendwas erfinden, was deinen Punkt stützt ;)
Ich möchte aber er selten, dass in meinem Haus Dachboden und Keller verwoben werden. Wäre doof, weil ich dazwischen wohne.

Wie soll ich mein Motoorradmotor mit der Sonneninnentemperatur verknüpfen, wenn beides in gleichem Modul liegt und ich das ganze OO gestalten möchte?
Unabhängig von Module: Dependency-Injection. (mit dem Zusatz, dass so ein Design trotzdem Bullshit ist)

also ich finde schon, dass man entweder 100%iges OO programmieren sollte, oder gar nicht.
Zumindest aber müsste es ja möglich sein 100%iges OO einschränkungslos programmieren zu können?, wenn es das Paradigma der heutigen Wahl ist?!^^
das findest *du*, aber zum Glück auch nur du ;)


Jetzt habe ich mal wieder ein praktisches Beispiel:
Dazu schreib ich gleich was
 
Zuletzt bearbeitet:
X

Xyz1

Gast
sind beides prozedurale Realisierungen. Nur das zweiteres eben Keywörter aus der objektorientierung verwendet, das ganze ressourcenfressender/langsamer ist und mir keine weiteren Vorteile einräumt.
Warum sollte ich dann Zweiteres verwenden?
Warum sollte ich allgemein irgendwas davon verwenden, wenn ich OO programmieren möchte?
Alles richtig!!!, zudem und, um das zu verkomplettieren.... bitte bedenken dass Java bei übermäßigem PP-Einsatz sehr langsam wird....

Prinzipiell lässt sich dein ganzer Beitrag auf nur dieses Zitat verkleinern....

Also.... schön erklärt - ich werde auch weiterhin lesen was du schreibst. :)
 

Meniskusschaden

Top Contributor
Und OO ist falsch, wenn man es nicht verstanden hat
Vermutlich kann man deshalb ein vermurkstes PP-Projekt länger am Leben halten bis es zum Kollaps kommt, als ein vermurkstes OO-Projekt. Wenn man möchte, kann man darin vielleicht einen Vorteil für die PP-Programmierung sehen. Ich finde es aber besser, wenn man möglichst früh erkennt, dass man Mist baut. Aus meiner Sicht also doch ein pro OO Argument.;) Allerdings sehe ich es tatsächlich als Vorteil der PP, dass man dafür mit einer geringeren Qualifikation auskommt. Das wiegt aber die Nachteile nicht auf.
 

mrBrown

Super-Moderator
Mitarbeiter
Jetzt habe ich mal wieder ein praktisches Beispiel:


Gehen wir mal davon aus ich baue einen Chat, ...
Den Teil hab ich mal hier ausgelagert, ist ja generell ein ganz interessantes Thema und unabhängig hiervon:
https://www.java-forum.org/thema/mo...r-von-oo-ist-gescheitert.182236/#post-1159377



Nein tatsächlich nicht, bin Informatik Student^^
An der Uni lernt man aber kein gutes Coding.
Das hängt sehr stark von der Uni und dem Studiengang ab ;)
Die Diskussion hier befindet sich aber nicht mal auf Coding-Ebene, sondern darüber. Und zumindest Modellierung sollte man auch in der Uni schon zumindest in Ansätzen lernen...
Aber ja (und da spreche ich für beide Seiten der Veranstaltungen), ich finde auch, dass der "Software Engineering"-Teil deutlich zu kurz kommt, betrifft an Unis leider nicht nur die Studierenden...


Rein aus Interesse, was studierst du? Nur "Informatik" oder irgendwas spezielleres?

Also wenn du nichts dagegen hast, könnten wir auch mal skypen/discorden/teamspeaken etc pp.
Eigentlich finde ich das hier angenehme - solche Diskussionen nur zu zweit finde ich immer etwas schade ;)
 
X

Xyz1

Gast
Vermutlich kann man deshalb ein vermurkstes PP-Projekt länger am Leben halten bis es zum Kollaps kommt,
Soll das ne Anspielung mit PP-Projekt auf mich sein, weil ich mich zumindest nicht (wie die anderen Teilnehmer der Diskussion) gegen PP-Projekte geäußert habe????
Allerdings sehe ich es tatsächlich als Vorteil der PP, dass man dafür mit einer geringeren Qualifikation auskommt.
Sehr blauäugig, bei Nicht-OO-Projekten von einer geringeren Qualifikation zu sprechen....
 

mrBrown

Super-Moderator
Mitarbeiter
Soll das ne Anspielung mit PP-Projekt auf mich sein, weil ich mich zumindest nicht (wie die anderen Teilnehmer der Diskussion) gegen PP-Projekte geäußert habe????
Ja, alles was in irgendeiner Art und Weise als Kritik verstanden werden könnte, meint immer, ohne Ausnahme, dich.

Sehr blauäugig, bei Nicht-OO-Projekten von einer geringeren Qualifikation zu sprechen....
Hat er nicht.
 
X

Xyz1

Gast
e31.jpg
 

knotenpunkt

Mitglied
Hey,

Ich habe erstmal eine Problemstellung, die ich lösen möchte.
Das *wie* (die Funktionalität) gibt die erstmal nicht vor.
Aus der Modellierung des Problems ergibt sich dann die Umsetzung. Die kann OOP sein, die kann PP sein, die kann FP sein. Wenn man aber Funktionalität beliebig von einer Umsetzung in die anderen umformen kann, kommt Bullshit raus - eben weil der wesentliche Schritt, die Modellierung, fehlt.

Ich setz dich auch nicht vor Schloss Neuschwanstein und lass dich das zu einem Hochhaus umbauen.

Ja aber von der Umsetzung aus, müsste ich ja wieder zurück zur Problemstellung kommen.
Somit kann ich die Problemstellung neu modellieren und so eine nicht bullshitkonforme Umwandlung von PP zu OO erreichen?^^


Wenn du die Kombination aus Verhalten und Daten als Prozedural siehst, kannst du das gern machen. Wenn du aber zwischen OOP und PP keinen Unterschied siehst, ist diese Diskussion hier ziemlicher Unsinn...

ActionObjects, eine Art Kombination aus Verhalten und Daten sehe ich definitiv als Prozedural an.
Du siehst das offensichtlich als OO an?

Da ActionObjects nichts anderes wie ein procedure-call sind, sind für dich diese auch OO?
wenn ich eine Prozedur aufrufe, dann kombiniere ich - zwar für kurzen Zeitraum - auch Daten und Verhalten.
Das Tolle an der Kombination ist, dass ich meist 100%ig das Single-Responsibility-Prinzip einhalte. Außerdem habe ich keine weiteren unnötigen Abhängigkeiten.
Alle Daten, die ich der Prozedur übergebe werden auch benötigt, um exakt diese Funktionalität auszuführen.

function x(this[a,b,c,d], sonstiges1)
function y(this[c,k,u,z], sonstiges2)

Die Prozeduren x und y sollen eine C-ähnliche Umsetzung (aus der Syntax Sicht) der Objektorientierung zeigen.

x benötigt die die daten a b c und d
y benötigt k u z und das gleiche Datum c, was auch von x benötigt wird.

Um x ausführen zu können, muss ich x aber auch unnötigerweise k, u und z zur Verfügung stellen
=> unnötige Datensturkopplung
Ausnahme: Das ganze würde ich dann in Kauf nehmen, wenn x und y nur Datenänderungen auf this ausführen, aber keine Seiteneffekte hat!
Von daher macht OO schon sinn, aber eben nur bei ADTS (abstrakte Datentypen), und damit meine ich bspw. irgendwelche Listen, Queues, Stacks etc pp.

Das ist noch ein anderer Aspekt, warum ich OO im Allgemeinen nicht als sehr sinnvoll erachte.

Anyway: ich gehe davon aus, dass du einen Prozeudurenaufruf nicht als OO ansiehst, auch wenn es das gleiche wie diese ActionObjects ist?!
Wie würdest du hier dann selbst zwischen OO und PP differenzieren?



Und in dem größerem System haben wir zwei vollkommen unabhängige Sonnensysteme. Die trotzdem vollen Zugriff aufeinander haben sollen?
Module sind schon sinnvoll. Aber OO macht den Eindruck, dass jedes Byte (Klasse) ein eigenes Modul darstellt.
Ok zwei vollkommen unabhängige Sonnensysteme haben keinen vollen Zugriff aufeinander. Wie würdest du nun in dem Modul Sonnsnesystem-Erde mit der Problemstellung Motorradmotor und Sonneninentemperatur sinnvoll in der OO umsetzen?

Also Klassen sind keine Module aber Klassen sind Module? Du solltest dich schon für eine Sichtweise entscheiden, auch wenn beide Begründbar sind...

Analog.
Modul != Prozedur
Und das ist das Problem: Jede Prozedur ist in sich genommen ein eigenes abgeschottetes Modul.
Das habe ich absichtlich so paradox stehen geschrieben^^

Meine Sichtweise ist die, dass es Unsinn ist, dass das was Klassen repräsentieren jeweils eigene Module sind.

Da ich jetzt aber eine Klasse Motorradmotor und eine Klasse Sonne habe, wie auch viele anderen Klassen noch dazwischen, macht das den Eindruck, weil es dir so schwer fällt diese zwei Dinge zusammenzubekommen, dass jede Klasse einem eigenen Modul entspricht.

Und das ist ja auch irgendwie so?!
Oder nicht?!

Die Frage gebe ich also an dich zurück, ist eine Klasse == Modul ODER ist Klasse !=Modul ?

Zu deiner Aussage, dass Modul==Prozedur:
Das ist doch super, so kann ich jede prozedur für sich genommen testen^^
Ausserdem kann ich die Prozeduren von überall aus aufrufen, ohne mich vorher durch langsame Graphenstrukturen hangeln zu müssen. (Zumal das ja eh nicht gewollt ist?, Siehe ein Beispiel nahe am Anfang dieses Threads hier und deine Aussage dazu^^)

Wenn ich jetzt Klassen verwende, dann verstecke ich Funktionalität hinter diesen. Bei verschachtelten Klassen komme ich von aussen erst gar nicht an innerere Klasse heran. Es sei denn ich baue riessige facadenhafte Delegationsstrukturen (das ist doch dann unübersichtlicher Code^^), oder ich baue ne get-chain (das selbe in blau^^), um an innere Klassen/Objekte zu kommen

Von daher jetzt auch mein Chat-Server-Beispiel.
Hier würde ich gerne mal von euch sehen, wo ihr die Funktionalität hinklatscht und wie auf diese zugegriffen werden kann^^



Nein, OO ist falsch, wenn es *keinerlei* Kapselung geben soll und dir alles völlig egal ist.
(Und OO ist falsch, wenn man es nicht verstanden hat, für dich also immer ;) )
Dann erklär doch mal auf ein Verständnis meinerseits zielend, die Objektorientierung^^



Was gibt denn give_me_bank eigentlich zurück?
Vielleicht ein Bank-Objekt?
Ein Bank-Objekt, ein Bank-Struct or whatever^^
give_me_bank(id,values[x,y,z])
das hier gibt bspw. nen bank-struct nur mit den Werten x y und z zurück

give_me_bank_info(id), das hier gibt mir nen Info text zur Bank mit der ID id zurück

transfer_money(bank_id1, bank_2, ktrn1, ktnr2, value, currency, automaticCurrencyTransformation);
Hier brauche ich keine Bankobjekte. Ausserdem interessiert es mich auch nicht wie das ganze gemacht wird.
Eventuell erledigt transfer_money das ganze sogar nur durch ein paar Datenbank-Queries
Auch um irgendwelche ACID-Regeln muss ich mir keine Gedanken machen
Das ist doch ne tolle Programmiert Art so^^

Ja klassische prozedurale Programmierung eben^^


Wer sagt, dass man das Objekt an der Stelle verwenden muss? Ist üblich, sowas im Programm rumzureichen.

Und wie gesagt, die eine Implementierung ist OO.
Da kann ich aber auch ein Struct herumreichen^^
Die Implementierung verwendet Keywords aus der OO, aber ist das wirklich OO?


Guck dir ein beliebiges Buch an, was sich mit OO beschäftigt. Können die besser erklären als ich (wird dich aber trotzdem nicht überzeugen^^)
Es ist auch ganz einfach: Immer, wenn du einem Objekt etwas übergibst, was es benötigt, ist es DI.
Jeder Konstruktor mit nicht primitiven Parametern ist DI.

Ja wenn DI das Non plus Ultra ist, dann passt doch dazu die prozeudurale Programmierung perfekt^^
Weil hier injecte ich wirklich IMMER und OHNE AUSNAHME^^ zur Laufzeit Daten in die Prozedur.

Sobald ich feste Strukuren verwende, fest angelegte Objektwelten, bin ich eingeschränkter, unflexibler (wenn ich mir die Flexibilität zurückholen möchte, bin ich unperfomanter).

Vielen anderen scheint das auch zu starr zu sein, von daher DI?
Warum aber nicht das höchste der Gefühle, das Flexibelste was es gibt? Eine Prozdur, in die ich wirklich jedes mal injecte?!!!!^^

DI, Services, ActionObjekts sind eindeutige Indizien dafür, dass sich die Leute gegen OO wehren!
Der Kampf gegen OO hat also schon begonnen.
Ich hoffe er wird auch zu Gunsten der prozeduralen Programmierung gewonnen^^

DI, Services, ActionsObjekts sind auch ein Zeichen dafür, dass sich Programmierer noch nicht ganz eingestehen möchten, dass OO einfach nicht gut ist und somit mit guter Miene zum bösen Spiel ein Art pseudo OO programmieren, das hoffenltich irgendwann wieder mehr ins reine prozedurale übergeht, was die Keywords betrifft, da es einfach perfomanter ist^^

Unabhängig von Module: Dependency-Injection. (mit dem Zusatz, dass so ein Design trotzdem Bullshit ist)
Mach doch mal ein konkretes Beispiel, wie derartiges aussehen könnte.
Folgender Anwendungsfall:
Motorrad soll explodieren, wenn er 7k Umdrehungen hat und die Sonneninnentemparatur sich zwischen temp x und temp y aufhält^^



das findest *du*, aber zum Glück auch nur du ;)
Also du sagst damit, dass du selbst auch prozedural programmierst?
In welchen Bereichen deiner Software, wird diese objektorientiert sein (und warum?), in welchen prozedural (und warum?)

Dazu schreib ich gleich was
Darauf werde ich dort dann später noch antworten^^

Rein aus Interesse, was studierst du? Nur "Informatik" oder irgendwas spezielleres?
Nur Informatik^^

Eigentlich finde ich das hier angenehme - solche Diskussionen nur zu zweit finde ich immer etwas schade ;)
Das eine schließt das andere ja nicht aus^^

ok soweit in diesem Thread hier mal wieder


lg knotenpunkt
 

mihe7

Top Contributor
userRight=......//lese aus der DB herauz welche Rechte der User hat
//.....

if(/*hier wird alles mögliche geprüft*/)

Das "hier wird alles mögliche geprüft" zeigt genau das Problem: Du bist hier nicht flexibel, sondern genau das Gegenteil ist der Fall. Machen wir das einmal konkreter:

Code:
if (canPost(userRight, room, command)) {
...
}

Die Logik ist fest im Code verankert. Diese Stelle im Programm ist abhängig von den Implementierungsdetails. Zur Übersetzungszeit steht genau fest, was wann passieren muss. Das Regelsystem ist starr. Soll daran etwas geändert werden, muss der Code geändert werden und dieses Modul neu übersetzt werden.

Und das lässt sich in OO sehr einfach umgehen:
Code:
interface PostPolicy {
    boolean canPost(...);
}

Der Code oben ändert sich damit zu:
Code:
if (policy.canPost(...)) {
}

Die Policy könnte z. B. per DI injected werden:
Code:
private PostPolicy policy;
public void setPolicy(PostPolicy p) { policy = p; }

Die betreffende Klasse arbeitet jetzt völlig unabhängig von Implementierungsdetails. Willst Du eine einfache Policy? Kein Problem, setze sie. Willst Du eine komplexe Policy? Ebenfalls kein Problem, setze sie.
 

mrBrown

Super-Moderator
Mitarbeiter
Ja aber von der Umsetzung aus, müsste ich ja wieder zurück zur Problemstellung kommen.
Somit kann ich die Problemstellung neu modellieren und so eine nicht bullshitkonforme Umwandlung von PP zu OO erreichen?^^
Äh, nein?

Wie kommt man denn von sowas:
Code:
{
data x;
data y;
data z;

switch(variable k)
case 1;//x und y werden verändert
case 2;//y und z werden verändert
usw
}
zu der dahinter stehenden Problemstellung?
Wenn du aus 3 beliebig benannten Variablen die Problemstellung erkennst, wundert es mich, dass du hier schreibst und nicht grad irgendwo mit einem vierstelligen Stundensatz arbeitest...

ActionObjects, eine Art Kombination aus Verhalten und Daten sehe ich definitiv als Prozedural an.
Du siehst das offensichtlich als OO an?
Ein Objekt welches einen gekapselten Zustand hat, und dem man Nachrichten schicken kann - ja, das sehe ich schon irgendwie als OO an (guck einfach noch mal auf deine Definition im Ursprungspost...).


Das nachfolgende ist dementsprechend Unsinn. Ein Prozeduraufruf macht aus eine Prozedur noch lange nichts OO-artiges, das ist völliger Unsinn jeglicher Definition nach.

Ok zwei vollkommen unabhängige Sonnensysteme haben keinen vollen Zugriff aufeinander. Wie würdest du nun in dem Modul Sonnsnesystem-Erde mit der Problemstellung Motorradmotor und Sonneninentemperatur sinnvoll in der OO umsetzen?
Und damit darfst du keinen globalen Zustand mehr haben (auch wenn global in diesem Fall auf ein Modul eingeschränkt ist, sondern musst es alles durchreichen.
Und das wäre auch die OO-Lösung: Dependency Injection (im einfachsten Fall mit Durchreichen).

Meine Sichtweise ist die, dass es Unsinn ist, dass das was Klassen repräsentieren jeweils eigene Module sind.
Aber Prozeduren (und damit auch Structs?) siehst du als einzelne Module an?

Da ich jetzt aber eine Klasse Motorradmotor und eine Klasse Sonne habe, wie auch viele anderen Klassen noch dazwischen, macht das den Eindruck, weil es dir so schwer fällt diese zwei Dinge zusammenzubekommen, dass jede Klasse einem eigenen Modul entspricht.
Wie bekommst du denn den Struct Motorradmotor und den Struct Sonne zusammen, die beide einzelnen Modulen entsprechen sollen?
Das was du beschreibst, ist kein OO-Problem.


Da kann ich aber auch ein Struct herumreichen^^
Die Implementierung verwendet Keywords aus der OO, aber ist das wirklich OO?
Du kannst ein Struct rumreichen, klar, aber mit Objekten hast du eben die zu den Daten gehörenden Funktionen, darum geht es doch ^^
Ja wenn DI das Non plus Ultra ist, dann passt doch dazu die prozeudurale Programmierung perfekt^^
Weil hier injecte ich wirklich IMMER und OHNE AUSNAHME^^ zur Laufzeit Daten in die Prozedur.
DATEN, bei OO injectest du Daten UND FUNKTIONEN auf diesen. Genau darum geht es doch.

DI, Services, ActionObjekts sind eindeutige Indizien dafür, dass sich die Leute gegen OO wehren!
Der Kampf gegen OO hat also schon begonnen.
Ich hoffe er wird auch zu Gunsten der prozeduralen Programmierung gewonnen^^
Eigentlich sind das alles Indizien, dass sie OO nutzen.
DI, Services, ActionObjekts SIND KEINE PP, es sind immer DATEN UND FUNKTIONEN - und mit einem ohne das andere kann man an der Stelle nichts anfangen.

Motorrad soll explodieren, wenn er 7k Umdrehungen hat und die Sonneninnentemparatur sich zwischen temp x und temp y aufhält^^

Code:
UnsinnigeExplosion : ExplosionsStrategie {
@Inject Motoradmotor motor
@Inject Sonne sonne

shouldExplode =>
motor.umdregungen > 7000 && sonne.innenTemp>y && sonne.innenTemp<y

}

Motorad {
@Inject ExplosionsStrategie explosionsStrategie

...
if explosionsStrategie.shouldExplode: explode()
...

}


Wie sieht denn die PP-Variante aus? (Und denk dabei an das von oben, Sonnensystem ist nicht global sichtbar^^)

Also du sagst damit, dass du selbst auch prozedural programmierst?
In welchen Bereichen deiner Software, wird diese objektorientiert sein (und warum?), in welchen prozedural (und warum?)
Mindestes die Main, weils nicht anders geht^^
z.B. Mathematische Funktionen, die sind nun mal selten Objekte...Aber soweit es geht ist der Code OO
 

httpdigest

Top Contributor
Tolle Antwort, @mihe7!
Sie zeigt sehr gut, dass OO eben auch etwas mit Abstraktion durch Polymorphie zu tun hat. Jetzt können die PostPolicies polymorh implementiert werden, womit man die Aufrufstelle von der konkret zu verwendenden Policy abstrahiert hat.
Ist ein schönes Beispiel, wie man mit OO dem hehren Ziel von Software Engineering, Code möglichst nur an wenigen Stellen ändern zu müssen, näher kommt. Klar kann man Polymorphie in prozeduralen Sprachen wie C auch über Function Pointer lösen (falls @knotenpunkt das gleich erwähnen möchte), aber die Function, die dann eine Implementierung einer Policy sein wird, benötigt ihrerseits ja auch Kontextinformationen, die statisch sind oder die sie sich von wo anders herholt oder injiziert bekommt und nicht immer mit jedem Aufruf mitgeschliffen werden sollten, weil das wieder den Nutzungscode abhängig von der Policy machen würde. Und dann sind wir beim Kapseln von Funktionen und Daten und sind bei... ja genau, OO!
Daraufhin kann man dann wieder erwidern: Ja, dann schleife ich eben ein Struct mit dem Aufruf mit, welches alle nötigen Daten für diese Funktion beinhaltet. Ja, das ist dann aber auch OO in Disguise: das Struct wäre dann nämlich eine Instanz einer Klasse.
 

knotenpunkt

Mitglied
Hey,

@mihe7

So hier muss ich wieder etwas weiter ausholen^^

Das was du beschreibst, kann ich syntaktisch eins zu eins mittels Funktionspointer (@httpdigest ) oder aber auch mit einem switch-case nachbilden.

Die Verwendung von polymorphen Klassen, Funktionspointern, oder switch-case-Konstruktionen verändert erstmal 0 am paradigma selbst.

Warum aber ist die swtich-case-Lösung die beste?

die Post-Policy (deine interface-lösung) reagiert je nach Typ unterschiedlich.
Mein switch-case(post-polcy-typ-as-integer) ganz genauso!.


Wenn ich die Post-Policy ändern möchte, dann muss ich den ganzen Typ austauschen.

Das funktioniert beim switch-case auch erstmal nicht anders.

Aber ich kann das switch-case jetzt umbauen in eine feingranularere IF-Konstruktion.

if(WetterAPI->tollesWetter() && ....){verwende folgende PostPolicy}
Diese API Abfrage passiert genau zu dem Zeitpunkt, wo ich auch die Post-Policy verwende, sprich es ist nicht nicht nur ein Konfigurat, sondern ein Teil des Algorithmus.

Und das ist mir ganz allgemein ein Problem in der OO. Dieser feste Zustand, die Konfiguration.


Aber um ganz genau zu sein, deine Post-Policy ist nur ein Wrapper um meine Prozedurale Programmierung.
Sie beschreibt mein Problem nicht in einer OO-Welt, sondern modularisiert nur meine prozedurale Welt.


Aber um nochmal zu deiner Post-Policy zurückzukommen.
Ok du hast jetzt 20 verschiedene Policies.

Du möchtest folgenden Batch-Prozess ausführen.

k;
for(-> 100k)
{
//jeder schleifenaufruf benötigt irgendwie eine andere policy
tmp=berechne benötigte policy
k->setPolicy(gemäß tmp)
k->doSth();
}

das ist doch krampf

warum nicht

k;
for(-> 100k)
{
//jeder schleifenaufruf benötigt irgendwie eine andere policy
tmp=berechne benötigte policy
k->doSth(tmp); // gemäß tmp, eventuell ein int wert, wird in doSth ein entsprechender algorithmus ausgeführt
}


beide for-schleifen machen exakt das gleiche, nur zweitere wird vermutlich schneller ausgeführt.
und ja in C++ gibts nicht ohne Grund zur Compile-Zeit festestehende Templates (generics) und den Hinweis
vtables (sprich polymorphe) Klassen zu vermeiden wo es nur geht.
//aber das soll jetzt nicht das Hauptthema hier sein


@mihe7 kannst du mir verraten, warum deine Konfigurationsklasse so viel mehr sinnvoller sein soll, als ein switch-case bzw. if, wo ich zur laufzeit feingranual den algorithmus flexibel bestimmen kann.

ja auch deine polymorphen klassen arbeiten zur laufzeit. Aber es ist geht Richtung unflexibel.
Da das Wort Konfiguration schon für sich alleine aussagt, da wird irgendwo was konfiguriert und das wird erstmal ne zeitlang gelassen.

ich binde mich mit jedem objekt das einen this-zeiger hat, erstmal an einen unflexiblen/festen state, wenn ich später auf diesem objekt ein doSth() ausführe.



Das nachfolgende ist dementsprechend Unsinn. Ein Prozeduraufruf macht aus eine Prozedur noch lange nichts OO-artiges, das ist völliger Unsinn jeglicher Definition nach.
warum?, in Java kann ich an eine Prozedur auch eine Wrapper-klasse von Int schicken etc pp,
so habe ich dann auch Daten mit Verhalten versendet.
Und genau das machen doch ActionObjects auch, bzw. Service-Klassen. Diese empfangen auch derartige Datensätze/Objekte^^

Und damit darfst du keinen globalen Zustand mehr haben (auch wenn global in diesem Fall auf ein Modul eingeschränkt ist, sondern musst es alles durchreichen.
Und das wäre auch die OO-Lösung: Dependency Injection (im einfachsten Fall mit Durchreichen).

Ok, kein globaler Zustand, wer ist aber dann verantwortlich dass die Daten an entsprechende Aktoren durchgereicht werden?


Aber Prozeduren (und damit auch Structs?) siehst du als einzelne Module an?
Ich glaube da haben wir uns etwas verhettert^^

Wie bekommst du denn den Struct Motorradmotor und den Struct Sonne zusammen, die beide einzelnen Modulen entsprechen sollen?
Das was du beschreibst, ist kein OO-Problem.
Ja das ist die Frage, wer kümmert sich darum, dass entsprechende Dinge, Daten, Objekte zusammenkommen?

Du kannst ein Struct rumreichen, klar, aber mit Objekten hast du eben die zu den Daten gehörenden Funktionen, darum geht es doch ^^
Funktionen welcher Art?
Und das ist die Frage.
Bei ADTS, abstrakten Datentypen akzeptiere ich es.
Aber bei allen anderen Datentypen, welche Art Funktionen hast du da, wenn du in deinem Programm Service-Klassen, etc pp einsetzt?


DATEN, bei OO injectest du Daten UND FUNKTIONEN auf diesen. Genau darum geht es doch.
und was machen diese FUNKTIONEN?^^

Eigentlich sind das alles Indizien, dass sie OO nutzen.
DI, Services, ActionObjekts SIND KEINE PP, es sind immer DATEN UND FUNKTIONEN - und mit einem ohne das andere kann man an der Stelle nichts anfangen.
wenn du services hast, dann sind die Funktionen denen die in die Service injecteten Objeten sehr spärlich.
Getter/Setter, vllt. noch ein paar objekteinschränkende Funktionen, wie setColor, welche aufpasst, dass keine falsche Farbe gesetzt wird, aber das wars doch schon?!



Wie sieht denn die PP-Variante aus? (Und denk dabei an das von oben, Sonnensystem ist nicht global sichtbar^^)
Diese injecteten Daten wie Motorradmotor und Sonne müssen ja irgendwo her kommen.
der Dependency-Injector-Manager muss diese ja irgendwie greifen können?^^
Wo bekommt Jener das her?

Was mache ich wenn ich mehrere Sonnen und Motorradmotore habe?
Was mache ich wenn erst zur Laufzeit bekannt wird, welche Sonne relevant ist?

Sprich der Motorradmotor hat über 7k Umdrehungen und im Spielchat schreibt jemand Sonne5
Erst dann soll die Abhängigkeit zur 5ten Sonne entstehen.
Oder ein Zufallsgenerator entscheidet welche Sonne relevant ist, zu dem Zeitpunkt wo sie relevant wird.

Wie würdest du das dann machen?




Soweit mal wieder



lg knotenpunkt
 

knotenpunkt

Mitglied
aber die Function, die dann eine Implementierung einer Policy sein wird, benötigt ihrerseits ja auch Kontextinformationen, die statisch sind oder die sie sich von wo anders herholt oder injiziert bekommt und nicht immer mit jedem Aufruf mitgeschliffen werden sollten, weil das wieder den Nutzungscode abhängig von der Policy machen würde. Und dann sind wir beim Kapseln von Funktionen und Daten und sind bei... ja genau, OO!

ok du hast das hier gekapselt, kannst dann aber auch nicht mehr wirklich im nutzungscode darauf reagieren

-> du wirst unflexibler



lg knotenpunkt
 

mrBrown

Super-Moderator
Mitarbeiter
Das was du beschreibst, kann ich syntaktisch eins zu eins mittels Funktionspointer (@httpdigest ) oder aber auch mit einem switch-case nachbilden.

Die Verwendung von polymorphen Klassen, Funktionspointern, oder switch-case-Konstruktionen verändert erstmal 0 am paradigma selbst.
Nein, das lässt sich nicht alles gleichartig Nutzen.

Polymorphie: Du hast Context des Ausrufers und des Aufgerufenen (Parameter und Instanzvariablen) und kannst beliebig, sogar zur Laufzeit, neue Typen einführen.
Funktionspointern: Du hast nur den Context des Aufrufes (Parameter), hast aber keinen zu der Funktion gehörenden Kontext (kann man nachbauen, aber wenn man OO nachbaut, warum nicht gleich richtige Polymorphie?)
Switch: Du hast wieder nur den Context des Aufrufes, aber bist dazu noch völlig statisch. Die Menge der Typen ist zur Compilezeit festgelegt, jede Änderung erfordert eine neu kompilieren.

Warum aber ist die swtich-case-Lösung die beste?

die Post-Policy (deine interface-lösung) reagiert je nach Typ unterschiedlich.
Mein switch-case(post-polcy-typ-as-integer) ganz genauso!.


Wenn ich die Post-Policy ändern möchte, dann muss ich den ganzen Typ austauschen.

Das funktioniert beim switch-case auch erstmal nicht anders.

Aber ich kann das switch-case jetzt umbauen in eine feingranularere IF-Konstruktion.

if(WetterAPI->tollesWetter() && ....){verwende folgende PostPolicy}
Diese API Abfrage passiert genau zu dem Zeitpunkt, wo ich auch die Post-Policy verwende, sprich es ist nicht nicht nur ein Konfigurat, sondern ein Teil des Algorithmus.

Und das ist mir ganz allgemein ein Problem in der OO. Dieser feste Zustand, die Konfiguration.
Irgendwie scheint dir zu entgehen, dass das Austauschen der Post-Policy keine Änderungen an irgendeinem bestehendem Code erfordert, deine switch-case oder if-Lösung dagegen schon.
Die Konfiguration der Post-Policy kann vollständig aus dem Code herausgehalten werden, es kann in irgendeiner Datei festgelegt sein, welche Post-Policy benutzt wird.

Um bei deinem Beispiel zu bleiben: statt Wetter soll jetzt die Position der ISS benutzt werden.
In deinem Fall: Code umschreiben, neu kompilieren, ganze Anwendung deployen.
Im OOP-Fall: eine neue Klasse anlegen und *nur* diese kompilieren, diese *eine* Klasse deployen, *eine* Zeile in einer *Konfigdatei* anpassen - fertig.

Und das ist mir ganz allgemein ein Problem in der PP. Der feste Algorithmus, der es völlig unflexibel macht.


Du möchtest folgenden Batch-Prozess ausführen.

k;
for(-> 100k)
{
//jeder schleifenaufruf benötigt irgendwie eine andere policy
tmp=berechne benötigte policy
k->setPolicy(gemäß tmp)
k->doSth();
}

das ist doch krampf

warum nicht

k;
for(-> 100k)
{
//jeder schleifenaufruf benötigt irgendwie eine andere policy
tmp=berechne benötigte policy
k->doSth(tmp); // gemäß tmp, eventuell ein int wert, wird in doSth ein entsprechender algorithmus ausgeführt
}
abgesehen davon, dass obiges natürlich auch als k->doSth(tmp) schreibbar ist:
Was Code umfasst denn in beiden Fällen doSth?
Mit OOP: keine Verzweigung oder ähnliches, sondern nur ein Methodenaufruf, eine neue Policy bedeutet, eine neue(!) Klasse anzulegen
Mit PP: ein Switch mit 100(!) Fällen und eine harte Kopplung an alle einzelnen policys, eine neue Policy bedeutet, bestehenden(!) Code zu ändern.


Da das Wort Konfiguration schon für sich alleine aussagt, da wird irgendwo was konfiguriert und das wird erstmal ne zeitlang gelassen.

Konfiguration != fest, Konfiguration kannst du im Gegensatz zu deinem fest kompilierten Algorithmus zur Laufzeit beliebig austauschen.

ich binde mich mit jedem objekt das einen this-zeiger hat, erstmal an einen unflexiblen/festen state, wenn ich später auf diesem objekt ein doSth() ausführe.
Und du findest das binden an "this" unflexibeler, als das binden an doSth()?

warum?, in Java kann ich an eine Prozedur auch eine Wrapper-klasse von Int schicken etc pp,
so habe ich dann auch Daten mit Verhalten versendet.
Und genau das machen doch ActionObjects auch, bzw. Service-Klassen. Diese empfangen auch derartige Datensätze/Objekte^^
Wie gesagt: Wenn du Objekte als Prozedural bezeichnen willst, gerne. Dann verlang aber nicht, das irgendwer anders auch OOP==PP sagt ;)

Ok, kein globaler Zustand, wer ist aber dann verantwortlich dass die Daten an entsprechende Aktoren durchgereicht werden?
der lokale Zustand?

Ja das ist die Frage, wer kümmert sich darum, dass entsprechende Dinge, Daten, Objekte zusammenkommen?
Verrat du es mir doch? Für dich scheint das ja in PP kein Problem zu sein?

Funktionen welcher Art?
Und das ist die Frage.
Bei ADTS, abstrakten Datentypen akzeptiere ich es.
Aber bei allen anderen Datentypen, welche Art Funktionen hast du da, wenn du in deinem Programm Service-Klassen, etc pp einsetzt?
Die, die zu dem entsprechendem Typ gehören?
Auf diese Frage gibt es keine generische Antwort, die gibt es eben nur bei ADT.
Bei einer Post-Policy könnte das zB die Abfrage der Rechte sein.

und was machen diese FUNKTIONEN?^^
wenn du services hast, dann sind die Funktionen denen die in die Service injecteten Objeten sehr spärlich.
Getter/Setter, vllt. noch ein paar objekteinschränkende Funktionen, wie setColor, welche aufpasst, dass keine falsche Farbe gesetzt wird, aber das wars doch schon?!
Dre Satz ergibt nicht wirklich Sinn...
Es sind *alle* Funktionen, die nicht mehrere verschiedene, getrennte Objekte umfassen.
Bei einer Post-Policy könnte das zB die Abfrage der Rechte sein.

Diese injecteten Daten wie Motorradmotor und Sonne müssen ja irgendwo her kommen.
der Dependency-Injector-Manager muss diese ja irgendwie greifen können?^^
Wo bekommt Jener das her?

Was mache ich wenn ich mehrere Sonnen und Motorradmotore habe?
Was mache ich wenn erst zur Laufzeit bekannt wird, welche Sonne relevant ist?
bei OO entscheidet sich das immer erst zur Laufzeit, das ist doch einer der zentralen Punkte...

Wenn du mehrere Sonnen und Motorradmotoren hast, hast du entweder mehrere vorgesehen, und es gibt zu einem Zeitpunkt mehrere, oder es gibt mehrere in unterschiedlichen Kontexten, aber pro Kontext eben nur einen.
Diesen Kontext kennt man natürlich, und dementsprechend erstellt man an irgendeiner Stelle passende Objekte bzw lässt sie erstellen.

Sprich der Motorradmotor hat über 7k Umdrehungen und im Spielchat schreibt jemand Sonne5
Erst dann soll die Abhängigkeit zur 5ten Sonne entstehen.
Oder ein Zufallsgenerator entscheidet welche Sonne relevant ist, zu dem Zeitpunkt wo sie relevant wird.

Motoradmotor hat einen Sonnen-Proxy. Ändert sich die Sonne des Kontextes, ändert sich der Proxy entsprechend.
Weder Motor noch Sonne müssen dabei etwas über den Kontext wissen.
Mit allen Handelsüblichen DI-Frameworks in Java abdeckbar ;)
 

mihe7

Top Contributor
Das was du beschreibst, kann ich syntaktisch eins zu eins mittels Funktionspointer (@httpdigest ) oder aber auch mit einem switch-case nachbilden.

Mit Function Pointer ja. Dann sind wir bei OO. Mit switch-Statements geht das nur statisch. Und "statisch" ist gerade nicht "dynamisch" :)

kannst du mir verraten, warum deine Konfigurationsklasse so viel mehr sinnvoller sein soll, als ein switch-case bzw. if, wo ich zur laufzeit feingranual den algorithmus flexibel bestimmen kann.

Du hast eine Abhängigkeit in Richtung Implementierungsdetail, ich nicht.

Die Sache ist doch ganz einfach: es wäre irgendwie ungünstig, wenn jedes Programm ein switch-Statement enthalten würde, das alle Druckermodelle dieser Welt kennt. Vom Aufwand mal abgesehen, würde dieses Programm mit neuen Druckermodellen ggf. nicht mehr funktionieren.

Die Prozedur, die das switch-Statement enthält, muss alle Prozeduren kennen, die dort aufgerufen werden. Willst Du eine neuen Drucker (oder eine neue Policy), musst du die switch-Prozedur ändern, damit der Drucker (die Policy) überhaupt berücksichtigt werden kann. Das ist nicht flexibel (s. o.), sondern für die Tonne (s. o.), auch weil man ständig Code ändern muss, der noch dazu mit der eigentlichen Aufgabe nichts zu tun hat.

Da das Wort Konfiguration schon für sich alleine aussagt, da wird irgendwo was konfiguriert und das wird erstmal ne zeitlang gelassen.

Und? Weil ich mir nach einem Jahr einen neuen Drucker kaufe, soll ich gleich eine neue Tabellenkalkulation und Textverarbeitung und Editoren und ... mitkaufen, weil dort ein switch-Statement verwendet wurde?!?
 

AndiE

Top Contributor
kannst du mir verraten, warum deine Konfigurationsklasse so viel mehr sinnvoller sein soll, als ein switch-case bzw. if, wo ich zur laufzeit feingranual den algorithmus flexibel bestimmen kann.

Wie soll das denn praktisch funktionieren. Wie will ich denn mit einem switch oder if festlegen, wer welchen Raum benutzen darf? Zuerst mache ich ein "switch(raum)" und dann z.B. bei "case 108:" eine "if-Abfrage" nach den Personalnummern? Um dann passgenau nur genau ausgewählten Leuten den Zugang zu gewähren? Wenn die Nr. 12345 9 Räume betreten darf, brauche ich dann nicht auch 9 abfragen. Wie teste ich, dass das auch funktioniet, und der Programmierer nicht irgendwo 12354 eingeben hat? Und wenn ein Professor neu ernannt wird?
 

knotenpunkt

Mitglied
hey,

Nein, das lässt sich nicht alles gleichartig Nutzen.

Polymorphie: Du hast Context des Ausrufers und des Aufgerufenen (Parameter und Instanzvariablen) und kannst beliebig, sogar zur Laufzeit, neue Typen einführen.
Funktionspointern: Du hast nur den Context des Aufrufes (Parameter), hast aber keinen zu der Funktion gehörenden Kontext (kann man nachbauen, aber wenn man OO nachbaut, warum nicht gleich richtige Polymorphie?)
Switch: Du hast wieder nur den Context des Aufrufes, aber bist dazu noch völlig statisch. Die Menge der Typen ist zur Compilezeit festgelegt, jede Änderung erfordert eine neu kompilieren.

und ja genau das ist eben mein Problem, der Kontext des Aufgerufenen. Das macht die Sache ja so unflexibel
Ausserdem:
Wie entscheide ich welche Daten ich als Instanzvariable in den Aufgerufenen binde und welche Daten ich schön flexibel von aussen hineinreiche?
Warum nicht gleich die größt möglichste Flexibilität nehmen und alle Daten von auẞen hineingeben?


Irgendwie scheint dir zu entgehen, dass das Austauschen der Post-Policy keine Änderungen an irgendeinem bestehendem Code erfordert, deine switch-case oder if-Lösung dagegen schon.
Die Konfiguration der Post-Policy kann vollständig aus dem Code herausgehalten werden, es kann in irgendeiner Datei festgelegt sein, welche Post-Policy benutzt wird.

Um bei deinem Beispiel zu bleiben: statt Wetter soll jetzt die Position der ISS benutzt werden.
In deinem Fall: Code umschreiben, neu kompilieren, ganze Anwendung deployen.
Im OOP-Fall: eine neue Klasse anlegen und *nur* diese kompilieren, diese *eine* Klasse deployen, *eine* Zeile in einer *Konfigdatei* anpassen - fertig.

Und das ist mir ganz allgemein ein Problem in der PP. Der feste Algorithmus, der es völlig unflexibel macht.

Das einzige was ich mit funktionispointern/polymorphe Klassen erreiche ist folgendes:
ich kann zur Laufzeit neu hinzukompilierte Programmstücke ins laufende Programm einpflanzen. (Da gebe ich dir vollkommen recht)
Wenn ich diese Praxis aber nicht unbedingt brauche, dann kann ich auch darauf verzichten.

Bei dem Switch-Case Szenario gebe ich dir auch recht, dass ich im Falle eines neuen Falls an entsprechender Stelle im Code eine Änderung im Sinne von einer Erweiterung vornehmen muss.
Aber ganz ehrlich, irgendwo muss festgelegt werden, welche in unserem Fall hier jetzt die Postpolicy aufgerufen wird. Ein Switch-Case geht jetzt etwas in die Richtung fixer Konfigurationsstate (wo man wirklich überlegen könnte das durch die performance-schlechtere Alternative bestehend aus polymorphen Klassen zu ersetzen).

Der Entscheidungsstate, also welche Postpolicy aufgerufen wird ist im Falle eines Switch-Case über eine switch(variable) festgelegt, im Falle von polymorphen Klassen eben postpolicy= ausgesuchtePostpolicy;

Beides setzt vorraus, dass vornherein entschieden worden ist, welche Postpolicy verwendet wird. Diese Entscheidung wird in irgendeinem Kontext fix abgespeichert. (fix im Sinne von, an dem Kontext wird nicht nach belieben rumgespielt. -> dadurch entsteht ne gewisse unflexibilität)


Möchte ich aber jetzt aus einem Request/Call/Whatever heraus entscheiden, welche Postpolicy verwendet wird, dann verzichte ich doch auf so nen festen state.

Der Request wird abgearbeitet und währenddessen wird entschieden welche Postpolicy relevant ist. Und das ist für mich hochdynamisch und schön prozedural.

Wie seht ihr das?


abgesehen davon, dass obiges natürlich auch als k->doSth(tmp) schreibbar ist:
Was Code umfasst denn in beiden Fällen doSth?
Mit OOP: keine Verzweigung oder ähnliches, sondern nur ein Methodenaufruf, eine neue Policy bedeutet, eine neue(!) Klasse anzulegen
Mit PP: ein Switch mit 100(!) Fällen und eine harte Kopplung an alle einzelnen policys, eine neue Policy bedeutet, bestehenden(!) Code zu ändern.

ja gut ich habe 100te postpolicys.......... für was?
Die postpolicys für sich alleine stehend sind doch wertlos

Klar das Switch-Case ist hier jetzt vereinfacht. Wie bereits oben geschrieben, soll nicht nur switch(variable) entscheiden welche postpolicy verwendet wird, sondern if(ziemlich viel) -> postpolicy


Konfiguration != fest, Konfiguration kannst du im Gegensatz zu deinem fest kompilierten Algorithmus zur Laufzeit beliebig austauschen.
vorrausgesetzt man möchte das.
Außerdem: ja es ist nicht fix..... mir gehts aber nicht darum hin und wieder mal was auszutauschen sondern feingranular zur laufzeit zu bestimmen was gerade Sache ist^^.....
Gleichen Konfigurationsstate den ich über viele calls hinweg verwende - zwar austauschen könnte -, ist für mich ein starres Gebilde.

Und du findest das binden an "this" unflexibeler, als das binden an doSth()?
Eine Gegenfrage beantwortet nicht meine Frage^^
dosth(blub, blab) bekommt zur Laufzeit entsprechende Daten (oft auch unterschiedliche Daten) und verhält sich entsprechend.
this wird vermutlich öfters gleiche daten (damit meine ich die Kontextdaten) haben und macht das ganze somit starr
falls this für jeden call bei this.dosth() andere daten hat, dann sind wir wieder bei meinen ActionObjects^^


der lokale Zustand?
das musste mir näher erklären, also was du damit meinst.

Verrat du es mir doch? Für dich scheint das ja in PP kein Problem zu sein?
Naja lch hole ich mir die Daten via einer anderen prozedur, die auf entsprechende Daten Zugriff hat.
Ob das dabei global oder über eine graph-verästelung oder Datenbank oder über whatever funktioniert spielt dabei keine Rolle.
(Das wichtige dabei ist zudem: ich hole mir in eine Hauptprozedur alle relevanten Daten um dann hier den Algorithmus zentral zu steuern.... Klar wenn ich den Algorithmus auf Unterprozeduren aufteilen kann, dann werde ich das natürlich machen)

Die, die zu dem entsprechendem Typ gehören?
Auf diese Frage gibt es keine generische Antwort, die gibt es eben nur bei ADT.
Bei einer Post-Policy könnte das zB die Abfrage der Rechte sein.
Naja ne Rechteabfrage bedeutet also du machst nen GetDaten-Aufruf.

Und von wo wird das aufgerufen?. Von einem Serviceobjekt nehme ich an?
-> Prozedurale Programmierung. Die Haupt-Programmlogik wird an zentraler Stelle verarbeitet.

Mich würde interessieren wie bei dir nen DoSth-Aufruf aussieht, der etwas komplexer ist.

Mit Function Pointer ja. Dann sind wir bei OO. Mit switch-Statements geht das nur statisch. Und "statisch" ist gerade nicht "dynamisch" :)

An der Stelle nochmal: Funktionspointer sind nicht objektorientiert.
Ja ich arbeite hier polymorph und zur Laufzeit Code austauschend.
Das hat aber mit der Objektorientierung im aAlgemeinen erstmal gar nichts zu tun.

Nur dadurch, dass ich polymorphe Klassen verwende, bin ich auch noch lange nicht objektorientiert.


Die Prozedur, die das switch-Statement enthält, muss alle Prozeduren kennen, die dort aufgerufen werden. Willst Du eine neuen Drucker (oder eine neue Policy), musst du die switch-Prozedur ändern, damit der Drucker (die Policy) überhaupt berücksichtigt werden kann. Das ist nicht flexibel (s. o.), sondern für die Tonne (s. o.), auch weil man ständig Code ändern muss, der noch dazu mit der eigentlichen Aufgabe nichts zu tun hat.
Irgendwo muss entschieden werden, welcher Drucker verwendet wird.
Wo wird das bei dir entschieden?

Wie soll das denn praktisch funktionieren. Wie will ich denn mit einem switch oder if festlegen, wer welchen Raum benutzen darf? Zuerst mache ich ein "switch(raum)" und dann z.B. bei "case 108:" eine "if-Abfrage" nach den Personalnummern? Um dann passgenau nur genau ausgewählten Leuten den Zugang zu gewähren? Wenn die Nr. 12345 9 Räume betreten darf, brauche ich dann nicht auch 9 abfragen. Wie teste ich, dass das auch funktioniet, und der Programmierer nicht irgendwo 12354 eingeben hat? Und wenn ein Professor neu ernannt wird?

Die Daten liegen natürlich nicht so im Code herum, sondern bspw. in einer Datenbank.
Entsprechende Algorithmen kann ich auch im Prozeduralen Stil schön modularisiert beherrschbar machen^^
Auch wenn ich jetzt statt nem if-else, switch-case etc pp polymorphe Klassen verwende, ist das nicht zwangsläufig objektorientiert.


Vllt. habe ich mich mit den switch-case/if(ziemlich vieles) VS polymorphe Klassen etwas zu weit aus dem Fenster gelehnt.
ABER im Grunde ist beides das gleiche und zweiteres nicht zwangsläufig objektorientiert.
Bei ersterem bin ich aber wesentlich flexibler, da ich aus dem Algorithmus heraus entscheide was Sache ist.
Zweiteres bedingt fast immer eine Vorkonfiguration und ist somit starr
Sieht man Zweiteres als Wrapper für Ersteres an (Naja ich habe ja nen prozeduralen Code hier reingeschrieben. Jemand hat dann die Postpolicy ins Spiel gebracht und meinen Code da rein gewrappt), dann habe ich eigentlich nichts verändert, sondern eben nur Code in irgend einen cool-aussehenden Code hineingewrappt.




Soweit mal wieder dazu


lg knotenpunkt
 

mihe7

Top Contributor
An der Stelle nochmal: Funktionspointer sind nicht objektorientiert.
Ja ich arbeite hier polymorph und zur Laufzeit Code austauschend.
Das hat aber mit der Objektorientierung im aAlgemeinen erstmal gar nichts zu tun.
Das ist der Kernpunkt von OO. Mir drängt sich allmählich der Eindruck auf: "Ja, ich arbeite polymorph, ich begrenze den Zugriff auf Daten, aber OO - Gott bewahre, nein OO ist das nicht, weil nicht sein kann, was nicht sein darf".

Bei ersterem bin ich aber wesentlich flexibler, da ich aus dem Algorithmus heraus entscheide was Sache ist.
Zweiteres bedingt fast immer eine Vorkonfiguration und ist somit starr

Wir drehen uns im Kreis.

Natürlich muss die Anwendung irgendwie "konfiguriert" werden. Du schreibst die Konfiguration fix in den Code. Andere machen den entsprechenden Code flexibel und konfigurieren ihn an anderer Stelle.

dann habe ich eigentlich nichts verändert, sondern eben nur Code in irgend einen cool-aussehenden Code hineingewrappt.

Du hattest gar keinen Code geliefert, insofern habe ich da auch nichts "hineingewrappt".

Geändert hat sich dadurch die Tatsache, dass der Code flexibel konfigurierbar ist. Ich muss dort nichts mehr ändern, um eine andere Policy verwenden zu können.
 

mrBrown

Super-Moderator
Mitarbeiter
und ja genau das ist eben mein Problem, der Kontext des Aufgerufenen. Das macht die Sache ja so unflexibel
Ausserdem:
Wie entscheide ich welche Daten ich als Instanzvariable in den Aufgerufenen binde und welche Daten ich schön flexibel von aussen hineinreiche?
Warum nicht gleich die größt möglichste Flexibilität nehmen und alle Daten von auẞen hineingeben?
Du musst deine Domäne vernünftig designen. Die Entscheidung, ob Instanzvariable oder Parameter, ergibt sich in so gut wie jedem Fall aus der Domäne.

Deine "Flexibilität" (die in OO nicht verloren geht), ist bei dir im wesentlichen ein Aufgeben aller sinnvollen Empfehlung für Programmstruktur. Kann man machen, in den letzten ~50 Jahren hat sich aber das Gegenteil durchgesetzt.

Ein Switch-Case geht jetzt etwas in die Richtung fixer Konfigurationsstate
Und das ist für mich hochdynamisch
Der Widerspruch fällt dir schon so ein bisschen auf?

Klar das Switch-Case ist hier jetzt vereinfacht. Wie bereits oben geschrieben, soll nicht nur switch(variable) entscheiden welche postpolicy verwendet wird, sondern if(ziemlich viel) -> postpolicy
Also wird der Code noch unübersichtlicher? Du hast jetzt 100 komplexe, eng verknüpfte Bedingungen - und das ist dir lieber als 100 vollkommen unabhängige Klassen, die jeweils genau eine Bedingung prüfen?

Außerdem: ja es ist nicht fix..... mir gehts aber nicht darum hin und wieder mal was auszutauschen sondern feingranular zur laufzeit zu bestimmen was gerade Sache ist^^.....
Gleichen Konfigurationsstate den ich über viele calls hinweg verwende - zwar austauschen könnte -, ist für mich ein starres Gebilde.
Und dir ist bisher nicht aufgefallen, dass es nichts starreres als ein Switch-Case gibt? Du weißt aber schon, was ein Switch ist?

Vllt. habe ich mich mit den switch-case/if(ziemlich vieles) VS polymorphe Klassen etwas zu weit aus dem Fenster gelehnt.
ABER im Grunde ist beides das gleiche und zweiteres nicht zwangsläufig objektorientiert.
Bei ersterem bin ich aber wesentlich flexibler, da ich aus dem Algorithmus heraus entscheide was Sache ist.
Zweiteres bedingt fast immer eine Vorkonfiguration und ist somit starr
Also, um deine Aussagen einmal umzuformulieren:

Im Algorithms hart kodiert haben, was passiert = flexibel
Einen konfigurierbaren Algorithmus haben, den man von außen verändern kann = unflexibel

Vielleicht sollten wir uns auf eine Definition von "flexibel" einigen, du scheinst eine sehr merkwürdige zu verwenden...
 

AndiE

Top Contributor
Wenn ich mir eine "boolean access ( string room, string pin)" vorstelle, dann gibt diese Funktion an, ob die Person mit der pin den Raum betreten darf. Um das zu gewährleisten, würde ich eine XML erstellen, wo ich dann menschenlesbar die Zutrittsberechtigungen reinschreibe. Nun stellt so eine XML aber eine hierachische Objektstruktur dar. Da ist dann wieder das O-Wort. Die Methode würde dann nämlich "boolean Room.access(string pin) heißen.
In rein PP gibt es aber maximal Arrays und Records. Theoretisch könnte ich in PP mit CSV eine Datei auslesen, die dann identische Tupel von Daten hat, die aber nicht zwingend strukturiert sind. Da kann es dann sein, dass der letzte Datensatz zeigt, dass die Person Zugriff hat. Änderungen sind hier schwer machbar, im Gegensatz zur XML.
 

knotenpunkt

Mitglied
hey,

Geht es hier noch weiter?

Die knotenpunktschen Mühlen mahlen langsam, aber sie mahlen.
Ja es geht weiter^^

Das ist der Kernpunkt von OO. Mir drängt sich allmählich der Eindruck auf: "Ja, ich arbeite polymorph, ich begrenze den Zugriff auf Daten, aber OO - Gott bewahre, nein OO ist das nicht, weil nicht sein kann, was nicht sein darf".
Nein das ist nicht der Kernpunkt von OO. Siehe anfängliche Definition.

Wir drehen uns im Kreis.

Natürlich muss die Anwendung irgendwie "konfiguriert" werden. Du schreibst die Konfiguration fix in den Code. Andere machen den entsprechenden Code flexibel und konfigurieren ihn an anderer Stelle.
Die Frage ist, was heißt Konfiguration?
Sowie ihr es versteht: Bspw. die Datenbankzugangsdaten für eine Datenbanklasse.
Oder die Farbe der Sonne, von der die Temperatur magischerweise mit meinem Motorradmotor verbunden ist^^

Was ist aber wenn sich derartige "Konfigurationen" erst zur Laufzeit gesetzt werden sollen?
Und zwar nicht perstistent gesetzt werden sollen.

Je nach Request, nach Kontextaufruf, ist meine Sonne mal blau mal gelb mal grün usw......
Abhängig davon was bei call_func(par1, par2, par3) par1 par2 und par3 ist, möchte ich eine andere Konfiguration vorliegen haben. DAS ist hochflexibel und nicht starr. So meine ich das!



Du hattest gar keinen Code geliefert, insofern habe ich da auch nichts "hineingewrappt".

Geändert hat sich dadurch die Tatsache, dass der Code flexibel konfigurierbar ist. Ich muss dort nichts mehr ändern, um eine andere Policy verwenden zu können.
Ja doch ein Pseudocode habe ich schon hingeschrieben. Und davon ausgehend hast du meinen Pseudocode als Grundlage genommen.


Und was bringt ein Austausch von einer Policy in eine andere, wenn folgendes gilt?:

In meinem code steht:

//Markierung I
{
if(par1&& par2 || par3 .......){do_sth1(parX);}
if(...){dot_sth2(parX);}
//also es wird zur Laufzeit hochdynamisch/hochflexibel entschieden was passieren soll.
}

Was du gemacht hast, ist folgendes:

etwasAustauschbares // das ist dein Wrapper
{
if(par1&& par2 || par3 .......){do_sth(parX);}
if(...){dot_sth2(parX);}
//also es wird zur Laufzeit hochdynamisch/hochflexibel entschieden was passieren soll.
}

etwasAustauschbares2
{
// was soll hier dann bitte stehen?
//wo brauche ich noch ne weitere policy....... ich habe ja alles oben in meinen if-kaskaden abgedeckt!
//hochflexibel wohlgemerkt!
}


stattdessen würdest du eventuell folgendes wollen:
die do_sth()-Einheiten werden bei dir zu den etwasAustauschbarenObjekten.

//Markierung II
if(par1&& par2 || par3 .......)
{
callObj= do_sth1_OBJ();
}
if(...)
{
callOBj=do_sth2_OBJ();
}

und später dann callOBj->action(X);


//problem welches in dieser Transformation auftaucht:
In Markierung I könnte es sein, dass sowohl do_sth1(X) als auch do_sth2(X) aufgerufen wird.
In Markierung II ist das so nicht mehr möglich. Das wäre ein weiterer negativer Seiteneffekt.

Aber auf was ich eigentlich hinaus möchte, ist das folgende:


Markierung II wird dann genommen, wenn etwas länger konfiguriert sein sollte, sprich diese ifs sehr selten aufgerufen werden. Was ist aber wenn diese ifs bei jedem CALL neu abgearbeitet werden sollen.
Dann ist doch Markierung II offensichtlich fehl am Platz.
Ich würde so bei jedem CALL sinnloserweise "neukonfigurieren".

Das macht II zwar nicht unflexibel, da es ja transformiert (fast) das gleiche ist wie I.
Aber es zeigt einen unperformanteren Programmaufbau und viel Overhead-Programmierarbeit.

Und sollte nicht bei jedem CALL das if neuausgewertet werden bei II, dann kann ich im übertragenem Sinne schon davon sprechen, dass OO unflexibler ist, da ich mich in diesem Falle auf eine starre Konfiguration verlasse, die selten geändert wird.


Du musst deine Domäne vernünftig designen. Die Entscheidung, ob Instanzvariable oder Parameter, ergibt sich in so gut wie jedem Fall aus der Domäne.
Da ich aber von Top to Down programmiere und nicht Bottom-Up, ist das halt nicht so cool.
Ausserdem möchte ich ja mein Programm auch zu jeder Zeit anpassen/erweitern können, ohne jedes mal alles refactoren zu müssen^^



Der Widerspruch fällt dir schon so ein bisschen auf?
Ich habe da ja etwas mehr dazu geschrieben^^.
Den Widerspruch der da vermeintlich zu erkennen ist, soll ja auch nur auf den ersten Blick so zu erkennen sein.
Wenn man weiterliesst, dann hebt sich dieser auf.
Bei mir bleibt der Widerspruch nicht starr und fix stehen. Ich schreibe auch im deutschen nicht objektorientiert, sondern ich schreibe prozedurale Texte. Die sind flexibel!^^


Also wird der Code noch unübersichtlicher? Du hast jetzt 100 komplexe, eng verknüpfte Bedingungen - und das ist dir lieber als 100 vollkommen unabhängige Klassen, die jeweils genau eine Bedingung prüfen?
Was bringen mir 100 unabhängige Klassen, von denen jede sein eigenes Brot bäckt?
Irgendwo müssen die Klassen wieder zusammengeführt werden. Siehst du das nicht auch so?

An der Stelle möchte ich natürlich sagen, dass ich Komponenten durchaus liebe. Hier trenne ich dann sehr wohl und es ist nicht mehr überall alles zugreifbar. Aber ich mache das nicht auf atomarer Ebene, wo jedes Staubkörnchen ein eigenes Biotop darstellen muss.

Ausserdem greife ich im prodeduralen auch nicht direkt auf irgendwelche Speicher, Daten zu, sondern gehe da immer serviceorientiert über eine Prozedur. Woher meine angefragte Prozedur seine Daten bekommt um mir meine Anfrage zu beantworten ist mir dabei egal. Es kann sich dabei um ein Speicherfeld im Hauptspeicher handeln. Es kann sich um einen Datenbankeintrag handeln. Es kann sich um ein Wert handeln, den die aufgerufene Prozedur über einen REST-Call oder Whatever bekommt.





Und dir ist bisher nicht aufgefallen, dass es nichts starreres als ein Switch-Case gibt? Du weißt aber schon, was ein Switch ist?
Ein Switch ist schnell in ein IF-ELSE umgeformt und die Entscheidungen die das IF-ELSE trifft hängen hochflexibel vom aufgerufenem Kontext ab!
So werden die Daten hineingegeben und das IF-ELSE reagiert je nachdem was die Parameter so an Daten beinhalten ENTSPRECHEND UND NICHT IMMER GLEICH, wie es bei einem starren vorkonfiguriertem objektorientierten Gebilde wäre.

Im Algorithms hart kodiert haben, was passiert = flexibel
Einen konfigurierbaren Algorithmus haben, den man von außen verändern kann = unflexibel

Siehe dieses Antwortschreiben^^
Ein konfigurierbarer Algorithmus wird nur selten umkonfiguriert. Und das macht die Sache im übertragenem Sinne unflexibler!


Wenn ich mir eine "boolean access ( string room, string pin)" vorstelle, dann gibt diese Funktion an, ob die Person mit der pin den Raum betreten darf. Um das zu gewährleisten, würde ich eine XML erstellen, wo ich dann menschenlesbar die Zutrittsberechtigungen reinschreibe. Nun stellt so eine XML aber eine hierachische Objektstruktur dar. Da ist dann wieder das O-Wort. Die Methode würde dann nämlich "boolean Room.access(string pin) heißen.
In rein PP gibt es aber maximal Arrays und Records. Theoretisch könnte ich in PP mit CSV eine Datei auslesen, die dann identische Tupel von Daten hat, die aber nicht zwingend strukturiert sind. Da kann es dann sein, dass der letzte Datensatz zeigt, dass die Person Zugriff hat. Änderungen sind hier schwer machbar, im Gegensatz zur XML.
Und jetzt kommt noch die Uhrzeit hinzu und vieles mehr.......

boolean access_room(roomId, roomPin, roomPin_benotigt, time, ......)
{
if(.......) return true;
return false;
}

Das Interessante dabei ist: es ist sowas von egal wie die prozedur intern arbeitet UND der Aufrufer braucht auch keine Instanz vom ROOM mit der roomId haben.
Ich kann die Prozedur zudem von überall aufrufen.

Bspw. wenn mein Motorradmotor für den Turbomodus wissen möchte, ob der Room mit der ID 7 aktuell accessable ist.

access_room(7,0,false, TIME,.....);

Der Motorradmotor braucht übrigens keine Instanz von Raum 7 haben.



Soweit mal wieder


lg knotenpunkt
 

mrBrown

Super-Moderator
Mitarbeiter
Nein das ist nicht der Kernpunkt von OO. Siehe anfängliche Definition.
Doch, Polymorphie ist der Kernpunkt der Definition.
Messages ist die Art von Polymorphie, die in der Sprache, von der die Definition abstammt, umgesetzt ist.

Die Frage ist, was heißt Konfiguration?
Sowie ihr es versteht: Bspw. die Datenbankzugangsdaten für eine Datenbanklasse.
Oder die Farbe der Sonne, von der die Temperatur magischerweise mit meinem Motorradmotor verbunden ist^^

Was ist aber wenn sich derartige "Konfigurationen" erst zur Laufzeit gesetzt werden sollen?
Und zwar nicht perstistent gesetzt werden sollen.

Je nach Request, nach Kontextaufruf, ist meine Sonne mal blau mal gelb mal grün usw......
Abhängig davon was bei call_func(par1, par2, par3) par1 par2 und par3 ist, möchte ich eine andere Konfiguration vorliegen haben. DAS ist hochflexibel und nicht starr. So meine ich das!

Wie kommst du immer auf die Idee, dass die Konfiguration irgendwie starr und perstistent hinterlegt ist? Das ist sie üblicherweise nicht.
DER zentrale Punkt von OOP ist Late Binding, das genaue Gegenteil von statischer Konfiguration. (und btw, auch wir meinen mit Konfiguration mehr als irgendwo hinterlegte Strings).

Das was du meinst, versteht dagegen niemand (außer ein paar theoretischen Informatikern...) als "Konfiguration" des Programms.

Wo kommen eigentlich deine Werte her? Hast du bisher noch nie wirklich dargelegt (also abseits von "hochflexibel", was bei dir wohl sowas wie "viele if" heißt...)

if(par1&& par2 || par3 .......){do_sth1(parX);}
if(...){dot_sth2(parX);}
Das ist schon per Definition nicht "hochflexibel". Eine hart programmierte Bedingung ist nicht flexibel. Und ja, ein par1&& par2 || par3 ....... ist hart programmiert!


stattdessen würdest du eventuell folgendes wollen:
Nein, würde er nicht.
(Ich kann dir versprechen, in @mihe7's Code wirst du keine solchen Ausprogrammierten if-Kaskaden finden)



Da ich aber von Top to Down programmiere und nicht Bottom-Up, ist das halt nicht so cool.
Ausserdem möchte ich ja mein Programm auch zu jeder Zeit anpassen/erweitern können, ohne jedes mal alles refactoren zu müssen^^
Also: du möchtest dir keine Gedanken über deine Software machen sondern einfach irgendwo programmieren und am Ende alle Möglichkeiten haben.

Soll ich dir was verraten?
Das hat nie funktioniert. Das funktioniert nicht. Das wird nie funktionieren.


Ein Switch ist schnell in ein IF-ELSE umgeformt und die Entscheidungen die das IF-ELSE trifft hängen hochflexibel vom aufgerufenem Kontext ab!
So werden die Daten hineingegeben und das IF-ELSE reagiert je nachdem was die Parameter so an Daten beinhalten ENTSPRECHEND UND NICHT IMMER GLEICH, wie es bei einem starren vorkonfiguriertem objektorientierten Gebilde wäre.
Nein. if-else ist nicht flexibel. Dort steht hart zur Compilezeit die Bedingung, das ist das genaue Gegenteil von Flexibel.
Ein konfigurierbarer Algorithmus wird nur selten umkonfiguriert. Und das macht die Sache im übertragenem Sinne unflexibler!
Also:
Ein konfigurierbarer Algorithmus ist unflexibel, weil man ihn nicht umkonfiguriert.
Aber ein nicht-konfigurierbarer Algorithmus ist flexibel, weil ... äh warum eigentlich?

Bspw. wenn mein Motorradmotor für den Turbomodus wissen möchte, ob der Room mit der ID 7 aktuell accessable ist.

access_room(7,0,false, TIME,.....);

Der Motorradmotor braucht übrigens keine Instanz von Raum 7 haben.
Ersetz ID mal mit Referenz (Die ID ist ja nichts anderes als eine Referenz auf den Raum?) und Instanz mal mit Referenz (das was man in z.B. Java hat, ist die Referenz auf die Instanz).

Fällt dir was auf?

Falls nein: Wie kommt denn die '7' in den Motorradmotor? (Und warum bestimmt der Motor, das er keine Pin braucht?)
 

mrBrown

Super-Moderator
Mitarbeiter
Ein kleiner (oder größerer) Tipp am Rande: Beschäftige dich doch mal Grundlegend mit Software Engineering.
Verschaff dir mal einen geschichtlichen Überblick von den Anfängen der Software-Entwicklung bis heute, was es da so für Probleme und Lösungen gab.


Das, was man von dir so liest, erweckt den Eindruck, dass du dich mit sowas noch nie wirklich beschäftigt hast und auch noch nicht mit größeren Programmen gearbeitet hast.
 

mihe7

Top Contributor
Nein das ist nicht der Kernpunkt von OO. Siehe anfängliche Definition.
Lies Dir mal http://www.purl.org/stefan_ram/pub/doc_kay_oop_en durch.

if(par1&& par2 || par3 .......){do_sth1(parX);}
if(...){dot_sth2(parX);}
//also es wird zur Laufzeit hochdynamisch/hochflexibel entschieden was passieren soll.
Du führst einen starren Satz von Bedingungen ein, auf den die Anwendung an dieser Stelle zur Laufzeit reagiert, um den Eindruck von Flexibilität zu erwecken.

Das ist wie bei einer Fernbedienung für den Fernseher: da habe ich Knöpfe mit if-Abfragen: if Knopf 1 gedrückt, then sende(CodeX) else if Knopf 2 gedrückt, then sende(Code Y), else if Knopf4 AND Knopf5 AND NOT Knopf6 gedrückt, sende(CodeZ) gesendet usw.

Jetzt kann ich sagen: hey, das ist ja ganz schön flexibel: die ganzen Knöpfe, die ich da drücken kann und was dann am Fernseher alles passiert.

Wie flexibel so eine Fernbedienung ist, sieht man in vermutlich jedem zweiten Wohnzimmer, wo gefühlte 25 Fernbedienungen auf dem Tisch liegen, weil keine (vernünftig) in der Lage ist, den TV, Receiver, Heimkino-Anlage, Rollos, usw. zu bedienen.

Vermutlich kommt jetzt der Einwand von Universalfernbedienungen. Die machen das Gesamtsystem tatsächlich etwas flexibler - aber nicht aufgrund ihrer if-Abfragen, sondern weil eine Fernbedienung (ein Objekt) über einen dummen Kommunikationskanal Nachrichten (hört, hört) mit dem Fernseher (ein anderes Objekt) "austauscht" und weder die Fernbedienung, noch der Fernseher Internas voneinander wissen müssen. Es reicht, wenn die Schnittstelle bekannt ist.
 

AndiE

Top Contributor
Das überzeugt mich nicht. Angenommen ich habe ein Uni, die eine Anzahl Gebäude enthält und ich werde beauftragt, eine Software zu schreiben, die den Zugang der Personen zu den Räumen verwaltet. Macht es da Sinn, dass der Programmierer die Zugangsregeln verwaltet? Ist es nicht entschieden sinnvoller, wenn ich dem Kunden, in diesem Fall die Institutsverwaltung, die Möglichkeit gebe, dies zu verwalten? Ich denke schon. Da die Räume aber in sich identisch sind, ist es doch schlau, eine Vorlage zu klonen. Da sind wir bei der Objektabbildung einer Klasse. Hier weiß der Raum, wer ihn betreten darf und gibt demjenigen die Erlaubnis. So wie ein Pförtner. Damit sind wir bei der Phrase: X will in Raum Y eintreten. Darf er das?" Und die Regeln dafür liegen in irgendwelchen Datenstrukturen und nicht in Strukturen. Das ist doch wahrhaftige Flexibilität oder?
 

Meniskusschaden

Top Contributor
Nein das ist nicht der Kernpunkt von OO. Siehe anfängliche Definition.
Dann solltest du diese anfängliche Definition vielleicht mal präzisieren, denn sie ist viel zu unscharf, um als Basis für eine so lang laufende Diskussion zu dienen. Hier ist ein Teil deiner Definition:
Vorab möchte ich definieren, was OO ist und was es nicht ist:

OO ist nicht: Polymorphy, Abstraktion, Vererbung, SOLID-Prinzipien,......
OO ist ein Paradigma wie man ganz generell eine Software aufbauen soll. Sprich in Klassen/Objekten, die sich dann später gegenseitig via Messages unterhalten.
Was meinst du nun beispielsweise mit "OO ist nicht Polymorphy"? Soll das heissen, OO ist nicht identisch mit Polymorphie? Da stimme ich dir zu. Es ist nicht dasselbe. Ein Auto ist kein Motor.
Oder soll es bedeuten, dass Polymorphie kein essentieller Bestandteil von OO ist? Da würde ich widersprechen. Ein Auto ohne Motor ist nicht sehr erfolgversprechend.

An diesem Punkt waren wir aber bereits vor sehr vielen Beiträgen und trotz vieler, langer Texte gab es eigentlich schon lange keine neuen Aspekte mehr - nur kaum nachvollziehbare Behauptungen darüber, was nun starr oder flexibel sei. Vielleicht solltest du auch mal eine greifbare Definition deiner Vorstellung von Flexibilität liefern. Hier ist mal ein kleines lauffähiges OO-Beispiel. Jedes Tier weiß selbst, wie es sich bewegen muß, kann sein Bewegungsverhalten bei Bedarf aber auch ändern. Wie würde dein PP-Pendant dazu denn aussehen?
Java:
public class Zoo {

    public static void main(String[] args) {
        Dog hasso = new Dog("Hasso");
        Animal[] animals = {hasso, new Dog("Bello"), new Fish("Fridolin"), new Fish("Nemo") };
        for (Animal animal : animals) {
            animal.move();
        }
        hasso.jumpIntoWater();
        System.out.println();
        for (Animal animal : animals) {
            animal.move();
        }      
    }
}

interface MotionStrategy {
    public void move();
}

class Running implements MotionStrategy {
    public void move() {
        System.out.println("läuft");
    }
}

class Swimming implements MotionStrategy {
    public void move() {
        System.out.println("schwimmt");
    }
}

abstract class Animal {
    private String name;
    MotionStrategy motionStrategy;
  
    public Animal(String name, MotionStrategy motionStrategy) {
        this.name = name;
        setMotionStrategy(motionStrategy);
    }
  
    public void setMotionStrategy(MotionStrategy motionStrategy) {
        this.motionStrategy = motionStrategy;
    }
  
    public void move() {
        System.out.print(name + " ");
        motionStrategy.move();
    }
}

class Dog extends Animal {
  
    public Dog(String name) {
        super(name, new Running());
    }
  
    public void jumpIntoWater() {
        motionStrategy = new Swimming();
    }
}

class Fish extends Animal {
  
    public Fish(String name) {
        super(name, new Swimming());
    }
}
 

knotenpunkt

Mitglied
hey,

Doch, Polymorphie ist der Kernpunkt der Definition.
Messages ist die Art von Polymorphie, die in der Sprache, von der die Definition abstammt, umgesetzt ist.

Nein das sehe ich nicht so, Polymorphie ist vllt. ein gutes Werkzeug, um die Konzepte der OO umzusetzen, jedoch das Werkzeug an sich, also die Polymorphie, ist nicht die OO.



Wie kommst du immer auf die Idee, dass die Konfiguration irgendwie starr und perstistent hinterlegt ist? Das ist sie üblicherweise nicht.
DER zentrale Punkt von OOP ist Late Binding, das genaue Gegenteil von statischer Konfiguration. (und btw, auch wir meinen mit Konfiguration mehr als irgendwo hinterlegte Strings).
Mach doch mal ein Beispiel .
In der Regel ist doch davon auszugehen, dass konfigurierte Objekte in der OO einen längeren Zeitraum existieren und nicht nur für die Dauer eines Requests, oder wie siehst du das?



Wo kommen eigentlich deine Werte her? Hast du bisher noch nie wirklich dargelegt (also abseits von "hochflexibel", was bei dir wohl sowas wie "viele if" heißt...)
Hochflexibel heisst bei mir nicht einen Algorithmus zu haben, dessen Ablauf weitestgehend von länger-existierendem State beeinflusst wird.

Das ist schon per Definition nicht "hochflexibel". Eine hart programmierte Bedingung ist nicht flexibel. Und ja, ein par1&& par2 || par3 ....... ist hart programmiert!
Du blendest hier das Große-Ganze aus.
Weiter unten werde ich das noch näher beschreiben.

Also: du möchtest dir keine Gedanken über deine Software machen sondern einfach irgendwo programmieren und am Ende alle Möglichkeiten haben.

Soll ich dir was verraten?
Das hat nie funktioniert. Das funktioniert nicht. Das wird nie funktionieren.
Also gibst du mir recht, dass jegliche Änderung/Erweiterung im OO-Kontext eines aufwädigen Refactoringprozesses bedarf?


Nein. if-else ist nicht flexibel. Dort steht hart zur Compilezeit die Bedingung, das ist das genaue Gegenteil von Flexibel.
So jetzt wird die ganze Sache spannend.

if-else sind Kontrollstrukturen, mit denen ich im wesentlichen meinen Algorithmus aufspanne.
Du sagst, man sollte derartiges nicht verwenden?
Wo und wie bitteschön konfigurierst du dann deine Objekte.

Wo und wie bitteschön bestimmst du dann später ganz konkret welcher deiner polymorphen Objekte an eine Variable gebunden werden sollen, auf dessen Grundlage du ja dann später weiterarbeiten wirst?

Du musst hier ganz genauso if-else verwenden.
if(........)
{
foo=so und so;
}
else
{
foo=ein anderes so und so;
}

später rufst du dann foo.doAction() auf!

so ich glaube ich muss einen neuen Begriff einführen:
Es gibt Dinge die zur Compilezeit entschieden werden.
Es gibt Dinge die zur Laufzeit entschieden werden.

Und genau zweiteres sollte ab jetzt genauer differenziert werden.
Es gibt Dinge, die sehr früh zur Laufzeit entschieden werden (Objektkonfiguration, DI, etc pp)
Es gibt Dinge, die unmittelbar vor der eigentlichen Ausführung entschieden werden (ein temporäres Action-Objekt, dass dann kurz ausgeführt wird und anschließend zerstört wird, nur dann sinnvoll, wenn die Ausführlocation wo anders ist..... dafür gibts aber auch Lambdas und Ähnliches)

Es gibt Dinge die zur Laufzeit entschieden werden (meine flexible Programmierung!)

Alle drei Arten wie Code zur Laufzeit ausgeführt wird, unterliegen der Tatsache, dass man hier if-else verwenden muss.

Die letzt genannte Option ist aber die flexibelste.
Warum? Siehe folgendes:

Also:
Ein konfigurierbarer Algorithmus ist unflexibel, weil man ihn nicht umkonfiguriert.
Aber ein nicht-konfigurierbarer Algorithmus ist flexibel, weil ... äh warum eigentlich?

Ein Algorithmus der konfigurierbar ist, aber sowieso bei jedem Request umkonfiguriert wird, ist erstmal nicht unflexibel. Aber die Tatsache dass er von vornherein konfiguriert worden ist, ist in dem Fall quatsch, weil ich ihn ja sowieso nach belieben "neu" konfiguriere und zwar jedesmal wenn er dran/bei jedem Request.

Und somit ist das so im Umkehrschluss nicht vorgesehen, dass ich ihn ständig umkonfiguriere!
=> Da das nicht vorgesehen ist => ist das ganze unflexibler!



Ersetz ID mal mit Referenz (Die ID ist ja nichts anderes als eine Referenz auf den Raum?) und Instanz mal mit Referenz (das was man in z.B. Java hat, ist die Referenz auf die Instanz).
Wenn du das schon so schreibst:
Warum dann nicht gleich access_Room als Methode in die Klasse Raum bauen?

Ganz einfach weil access_room viel komplexer aufgebaut ist, und vllt. nicht nur die Raum-Daten benötigt sondern von vielen anderen Objekten auch noch Daten. => ich baue eine Prozedur, die den Raum bekommt und viele andere Objekte auch noch, um dann zu entscheiden, ob ein Zugriff gewährt wird


Zu deiner Frage mit der ID und Instanz:
Vllt. existiert der Raum ja gar nicht auf meinem HEAP, sondern in der Datenbank, oder er ist nur via eines REST-Calls oder Whatever zu erreichen. Jetzt kommt dann vermutlich von deiner Seite wieder die Argumentation, dass in dem Fall der Raum ein Proxy ist. Finde ich aber nicht so hübsch, eine ID ist viel schlanker als ne Instanz proxy_Raum im Speicher zu halten. Vllt. existiert der Informationsträger, der die ID zum Raum besitzt gerade gar nicht selbst im Speicher. Das heisst ich müsste in dem Fall erstmal nen Rießen Objektgraphen in den Speicher setzen, um dann access_room auszuführen. Direkte Datenbankoptimierungen sind so dann nicht mehr vorgesehen.


Falls nein: Wie kommt denn die '7' in den Motorradmotor? (Und warum bestimmt der Motor, das er keine Pin braucht?)
Weil ich das so bestimmt habe, dass der Motor keinen PIN braucht?
Kreativität ist in der OO scheinbar nicht gern gesehen^^ => Unflexibiltät^^
Die 7 ist auch von mir, ist halt in dem Beispiel jetzt einfach mal hart codiert, muss später natürlich nicht so sein.
Wie würde eine Objektinstanz da so einfach reinkommen?, wo ich doch nichtmal alle Türen im Speicher vorhalten möchte?

Das, was man von dir so liest, erweckt den Eindruck, dass du dich mit sowas noch nie wirklich beschäftigt hast und auch noch nicht mit größeren Programmen gearbeitet hast.
Also ich hätte da wirklich mal Lust mit dir zu skypen. Die öffentliche Diskussion hier und mal ne private mit Dir schließen sich ja nicht gegenseitig aus.

Du führst einen starren Satz von Bedingungen ein, auf den die Anwendung an dieser Stelle zur Laufzeit reagiert, um den Eindruck von Flexibilität zu erwecken.

Das ist wie bei einer Fernbedienung für den Fernseher: da habe ich Knöpfe mit if-Abfragen: if Knopf 1 gedrückt, then sende(CodeX) else if Knopf 2 gedrückt, then sende(Code Y), else if Knopf4 AND Knopf5 AND NOT Knopf6 gedrückt, sende(CodeZ) gesendet usw.

Jetzt kann ich sagen: hey, das ist ja ganz schön flexibel: die ganzen Knöpfe, die ich da drücken kann und was dann am Fernseher alles passiert.

Wie flexibel so eine Fernbedienung ist, sieht man in vermutlich jedem zweiten Wohnzimmer, wo gefühlte 25 Fernbedienungen auf dem Tisch liegen, weil keine (vernünftig) in der Lage ist, den TV, Receiver, Heimkino-Anlage, Rollos, usw. zu bedienen.

Vermutlich kommt jetzt der Einwand von Universalfernbedienungen. Die machen das Gesamtsystem tatsächlich etwas flexibler - aber nicht aufgrund ihrer if-Abfragen, sondern weil eine Fernbedienung (ein Objekt) über einen dummen Kommunikationskanal Nachrichten (hört, hört) mit dem Fernseher (ein anderes Objekt) "austauscht" und weder die Fernbedienung, noch der Fernseher Internas voneinander wissen müssen. Es reicht, wenn die Schnittstelle bekannt ist.
Ich habe nie gesagt, dass ich allgemein etwas gegen Polymorphie habe.
Funktionspointer/Lambdas und so setze ich sehr gerne ein.
Aber das macht noch lange kein prozedurales Programm zu einem Objektorientierten.

Das überzeugt mich nicht. Angenommen ich habe ein Uni, die eine Anzahl Gebäude enthält und ich werde beauftragt, eine Software zu schreiben, die den Zugang der Personen zu den Räumen verwaltet. Macht es da Sinn, dass der Programmierer die Zugangsregeln verwaltet? Ist es nicht entschieden sinnvoller, wenn ich dem Kunden, in diesem Fall die Institutsverwaltung, die Möglichkeit gebe, dies zu verwalten? Ich denke schon. Da die Räume aber in sich identisch sind, ist es doch schlau, eine Vorlage zu klonen. Da sind wir bei der Objektabbildung einer Klasse. Hier weiß der Raum, wer ihn betreten darf und gibt demjenigen die Erlaubnis. So wie ein Pförtner. Damit sind wir bei der Phrase: X will in Raum Y eintreten. Darf er das?" Und die Regeln dafür liegen in irgendwelchen Datenstrukturen und nicht in Strukturen. Das ist doch wahrhaftige Flexibilität oder?
Richtig die Daten liegen am besten in einer Datenbank.
Die Prozeduren, die dann mit den Daten arbeiten ,müssen die Räume ja nicht unterschiedlich behandeln.
Sollte ich aber eine komplexe Ablaufsteuerung benötigen, dann wäre das wesentlich einfacher in prozedural organisierten Welt als in einer objektorientierten Welt umsetzbar.

Was meinst du nun beispielsweise mit "OO ist nicht Polymorphy"? Soll das heissen, OO ist nicht identisch mit Polymorphie? Da stimme ich dir zu. Es ist nicht dasselbe. Ein Auto ist kein Motor.
Oder soll es bedeuten, dass Polymorphie kein essentieller Bestandteil von OO ist? Da würde ich widersprechen. Ein Auto ohne Motor ist nicht sehr erfolgversprechend.
Ich glaube das habe ich ganz am Anfang dieses Beitrags hier bereits beantwortet^^



@Meniskusschaden
zu deinem Code:

Das ist ungefähr das pentadent hierzu:

Du hast nen User: Einer davon ist normaler User, der andere Admin
und je nach Usertype verhalten sich diverse Funktionen anders.

Statt irgendwo dann if(usertype=="admin"){} zu schreiben, hast du einen polymorphen Code, ABER in OO Manier.
Das beantwortet auch schon deine Frage, wie ich es prozedural programmieren könnte.

Dein Code in OO Manier hat aber ein paar Probleme (damit meine ich nicht unlösbar, aber einfach nur ne hässliche Transformation und viel Overhead, um folgende Problemstellung in OO auszudrücken)


Du hast nen Algorithmus, erstmal sehr generisch! Und dann kommt spezifischer Code, den ich aber im Entwicklungsprozess schön mit dem generischen verzahnen möchte, sodass das TemplatePattern hier nicht so einfach funktioniert. Zumal das eh schon wieder unnötiger Overhead wäre.

....
....
.... // hier sind kontextdaten, die gleich in folgendem block mitverwendet werden sollen
if(usertype=="admin")
{
//also hier
}
....
....
....

//so und eventuell hast du dann auch noch das hier:

if(usertype=="admin")
{
...
...
if(usertype2=="IRGNDWAS")
{
....
}
....
}
....
....
....


Jetzt bin ich gespannt, wie du diesen verchachtelten Algorithmus in einen polymorphen OO-Aussehenden transformieren möchtest.


Zudem, was ich an solchen Beispielen immer hasse, an einem das du mir gegeben hast, und was auch im Designpattern-Buch so verwendet wird:

System.out.println IST global!
Und hat in einem konsistentem OO-Beispiel eigentlich nichts verloren.

Die Frage, die sich zudem ergibt:
Du hast da jetzt sehr einfache Methodenaufrufe, wie move()

Gehen wir mal davon aus, du hättest da nen wesentlich komplexeren Algorithmus
moveKomplex(....), der sich dann nicht mehr einem dieser Typen zuordnen lässt.
Dazu kommt dass dieses moveKomplex je nach Parameterwerte nicht nur ein Tier bewegen lässt und eine Transaktionssicherheit möchte ich auch noch haben. Falls es irgendwo Probleme gibt -> Rollback!

Also ein Algorithmus für den man klassischerweise eine Serviceklasse benötigt.
Wie würdest du es dann machen: Wie Polymorphie und OO sowie die Tatsache, dass du eine Serviceklasse benutzt, in Einklang bringen?


Soweit mal wieder



lg knotenpunkt
 

AndiE

Top Contributor
Was heißt den "flexibel"? Wir haben bei oben genanntem Beispiel eine Anzahl Räume und eine Anzahl Personen. Offensichtlich kann ich die Personen in Gruppen zusammenfassen. Somit hat z.B. für den Raum 128 der Professor A alle Rechte, die Studenten der Klasse B das Recht zum Türöffnen und der Hausmeister H das Recht, die E-Anlage zu bedienen. Um das einzustellen, benötige ich nur das Programm, das im Speicher verschiedene Tupel hinterlegt. Die Änderung der Zugriffe wird nur durch Änderung der Tupel eingerichtet.
Damit ist das Programm für mich hochflexibel, da sein Verhalten einerseits innerhalb des Anwendungsfalles schnell geändert werden kann und auch problemlos auf einen anderen Anwendungsfall( anderes Gebäude, andere Struktur der Belegschaft) geändert werden kann.
Offensichtlich benötige ich nur eine Struktur aus n Sensoren und m Aktoren und k Identifizierungsobjekten( Zutrittskarten, RFID usw.).

Ist das nicht flexibel genug? Man kann auch mit einem Schraubendreher, keine Wand anmalen.
 

Meniskusschaden

Top Contributor
Was meinst du nun beispielsweise mit "OO ist nicht Polymorphy"? Soll das heissen, OO ist nicht identisch mit Polymorphie? Da stimme ich dir zu. Es ist nicht dasselbe. Ein Auto ist kein Motor.
Oder soll es bedeuten, dass Polymorphie kein essentieller Bestandteil von OO ist? Da würde ich widersprechen. Ein Auto ohne Motor ist nicht sehr erfolgversprechend.
Ich glaube das habe ich ganz am Anfang dieses Beitrags hier bereits beantwortet^^
Nein, leider nicht. Hier:
Nein das sehe ich nicht so, Polymorphie ist vllt. ein gutes Werkzeug, um die Konzepte der OO umzusetzen, jedoch das Werkzeug an sich, also die Polymorphie, ist nicht die OO.
hast du wie in deinem Eröffnungsthread wieder nur behauptet, Polymorphie sei nicht OOP. Und wie in deinem Eröffnungsthread hast du auch jetzt wieder offen gelassen, was du damit meinst. Mein Verständnisproblem habe ich einfach und deutlich beschrieben. Du willst es offensichtlich nicht aufklären.

Ich habe nie gesagt, dass ich allgemein etwas gegen Polymorphie habe.
Funktionspointer/Lambdas und so setze ich sehr gerne ein.
Aber das macht noch lange kein prozedurales Programm zu einem Objektorientierten.
Doch, genau das tut es an der Stelle. Man hat natürlich schon zu Zeiten der PP erkannt, dass man flexibler wird, wenn man objektorientiert programmiert und hat das deshalb auch bereits damals praktiziert. Daraus ist der Bedarf für bessere Sprachunterstützung für Polymorphie entstanden und man hat dieses Defizit der PP-Sprachen beseitigt, indem man sie zu OOP-Sprachen weiter entwickelt hat. Das ist die ganz normale technologische Evolution. Deshalb ist auch deine früher mal geäußerte Forderung, in der OOP-Programmierung keine PP zu verwenden, ungefähr so sinnvoll, wie die Forderung, man solle keine Autos mit Rädern bauen, weil die ja bereits für Kutschen verwendet würden, die schließlich schon lange vor den Autos erfunden wurden. Und ja: solche Autos wären ziemlich nutzlos und ich werde das Gefühl nicht los, dass genau das der Grund ist, warum du OOP sinnlos findest.

so ich glaube ich muss einen neuen Begriff einführen:
Es gibt Dinge die zur Compilezeit entschieden werden.
Es gibt Dinge die zur Laufzeit entschieden werden.
Das ist nicht neu, sondern bereits seit dem ersten Beitrag das Thema.

Es gibt Dinge die zur Laufzeit entschieden werden (meine flexible Programmierung!)
Nein. In deinen Beispielen wird alles zur Compilezeit entschieden. Es gibt nur die n Fälle, die zur Compilezeit ausprogrammiert sind. Welche davon bei einer Programmausführung durchlaufen werden, wird zwar erst zur Laufzeit entschieden, aber es können nur diese n Fälle sein. Das ist ein wesentlicher Unterschied zu echter Polymorphie.

@Meniskusschaden
zu deinem Code:

Das ist ungefähr das pentadent hierzu:

Du hast nen User: Einer davon ist normaler User, der andere Admin
und je nach Usertype verhalten sich diverse Funktionen anders.
Nein, ich erkenne da keinen Zusammenhang zu meinem Beispiel.

Statt irgendwo dann if(usertype=="admin"){} zu schreiben, hast du einen polymorphen Code, ABER in OO Manier.
Das beantwortet auch schon deine Frage, wie ich es prozedural programmieren könnte.
Nein, leider hast du auch das nicht beantwortet.

Du hast nen Algorithmus, erstmal sehr generisch! Und dann kommt spezifischer Code, den ich aber im Entwicklungsprozess schön mit dem generischen verzahnen möchte, sodass das TemplatePattern hier nicht so einfach funktioniert. Zumal das eh schon wieder unnötiger Overhead wäre.
Ich habe das Template-Pattern überhaupt nicht verwendet, sondern das Strategie-Muster. Es geht hier um den Algorithmus in der main-Methode, der (abgesehen von der für das schlichte Beispiel primitiv gehaltenen Objekterzeugung) nie wieder geändert werden muß, unabhängig davon, ob andere Tierarten oder anderes Bewegungsverhalten hinzu kommt oder sich etwas daran ändert. Und ja: es kann sein, das zur Implementierung des konkreten Verhaltens hier und da auch if-Abfragen verwendet werden. Das ist ja nicht verboten, wenn es sachgerecht ist. Den Algorithmus in main() geht das aber nichts an.

Zudem, was ich an solchen Beispielen immer hasse, an einem das du mir gegeben hast, und was auch im Designpattern-Buch so verwendet wird:

System.out.println IST global!
Und hat in einem konsistentem OO-Beispiel eigentlich nichts verloren.
Unabhängig davon, ob deine Aussage stimmt, ist das hier völlig irrelevant. Es ist doch offensichtlich, dass das in meinem Beispiel und auch in den meisten Büchern oder anderen Beispielen nur stellvertretend für die eigentliche Methodenimplementierung steht. Das kann doch wohl unmöglich ernsthaft das Niveau sein, auf dem du diskutieren willst.

....
....
.... // hier sind kontextdaten, die gleich in folgendem block mitverwendet werden sollen
if(usertype=="admin")
{
//also hier
}
....
....
....

//so und eventuell hast du dann auch noch das hier:

if(usertype=="admin")
{
...
...
if(usertype2=="IRGNDWAS")
{
....
}
....
}
....
....
....


Jetzt bin ich gespannt, wie du diesen verchachtelten Algorithmus in einen polymorphen OO-Aussehenden transformieren möchtest.
Wenn du mal konkret wirst, kann man vielleicht auch konkret darauf antworten. So kann man nur sagen, dass das Admin-Objekt, die Tatsache, dass der usertype2="IRGENDWAS" ist, eben entsprechend behandeln muß. Vielleicht tatsächlich mittels einer Verzweigung, vielleicht auch anders - jedenfalls auf eine Weise, die den Aufrufer nichts angeht, damit der sich nicht auch noch darum kümmern muss.
 

mihe7

Top Contributor
@knotenpunkt das Problem dieser Diskussion ist, dass Du die Frage stellst, ob OO nach Alan Kay gescheitert wäre und gleichzeitig seine Definition nicht zulässt. Wie soll das funktionieren?

Ich habe nie gesagt, dass ich allgemein etwas gegen Polymorphie habe.
Funktionspointer/Lambdas und so setze ich sehr gerne ein.
Aber das macht noch lange kein prozedurales Programm zu einem Objektorientierten.
Aha... Wir sind also wieder an dem Punkt: ich programmiere zwar objektorientiert aber - da das nicht sein darf - nenne ich es prozedural.

Lassen wir die Buzzwords doch einfach mal weg: Du sicherst den Zugriff auf Deine Daten ab und verwendest Function Pointer, ich verwende if-else. Wo liegt jetzt gleich nochmal das Problem? :)
 

Meniskusschaden

Top Contributor
@knotenpunkt : Nebenbei bemerkt verfehlt deine gesamte bisherige Diskussionsführung das Thema, weil du ja eigentlich zeigen wolltest, dass die OOP gescheitert sei. Dazu genügt doch nicht dein bisheriger Versuch, Beispiele zu finden, die sich mit PP besser lösen lassen. Das würde höchstens zeigen, dass PP nicht sinnlos ist. Für deine These müsstest du nachweisen, dass es keine Probleme gibt, die sich mit OOP besser als mit PP lösen lassen.
 
X

Xyz1

Gast
Was ist das hier für ein langes Thema ohne nennenswerten Mehrwert?:confused:
Habe ich hier schonmal geantwortet, wieso bekomme ich Benachrichtigungen?:confused:

Das Funktionale Paradigma ist sicher auch gut - es mag nur keiner
 

mrBrown

Super-Moderator
Mitarbeiter
Nein das sehe ich nicht so, Polymorphie ist vllt. ein gutes Werkzeug, um die Konzepte der OO umzusetzen, jedoch das Werkzeug an sich, also die Polymorphie, ist nicht die OO.
Wie schon mehrmals gesagt:
Diese, von dir genannte, Definition:
OO ist ein Paradigma wie man ganz generell eine Software aufbauen soll. Sprich in Klassen/Objekten, die sich dann später gegenseitig via Messages unterhalten.

ist Polymorphie. Nicht so, wie man es aus Java kennt, aber trotzdem Polymorphie.

In der Regel ist doch davon auszugehen, dass konfigurierte Objekte in der OO einen längeren Zeitraum existieren und nicht nur für die Dauer eines Requests, oder wie siehst du das?
Nein, in der Regel ist davon auszugehen, dass Objekte einen möglichst kleinen Scope & Lebenszyklus haben. (Keine Ahnung, was du immer mit Konfiguriert meinst...)

Also gibst du mir recht, dass jegliche Änderung/Erweiterung im OO-Kontext eines aufwädigen Refactoringprozesses bedarf?
Nein. Jede größere Änderung der Anforderungen zieht Refactoring nach sich. Und je stärker gekoppelt der Code, desto schlechter ist das durchführbar.
Ob das OOP, PP oder FP ist, macht dabei keinen Unterschied.

Es gibt Dinge die zur Compilezeit entschieden werden.
Es gibt Dinge die zur Laufzeit entschieden werden.

Und genau zweiteres sollte ab jetzt genauer differenziert werden.
Es gibt Dinge, die sehr früh zur Laufzeit entschieden werden (Objektkonfiguration, DI, etc pp)
Es gibt Dinge, die unmittelbar vor der eigentlichen Ausführung entschieden werden (ein temporäres Action-Objekt, dass dann kurz ausgeführt wird und anschließend zerstört wird, nur dann sinnvoll, wenn die Ausführlocation wo anders ist..... dafür gibts aber auch Lambdas und Ähnliches)

Es gibt Dinge die zur Laufzeit entschieden werden (meine flexible Programmierung!)

* Objektkonfiguration, DI, etc pp wird im Idealfall möglichst spät entschieden ("so spät wie möglich, so früh wie nötig").
* "deine flexible Programmierung" wird zur Compilezeit festgelegt. Die genauen Bedingungen schreibst du in den Code, und diese Bedingungen sind die ganze Laufzeit über fest und werden sich niemals ändern.

Definition aus dem Duden:
https://www.duden.de/rechtschreibung/flexibel hat gesagt.:
an veränderte Umstände anpassungsfähig

In wie fern ist das auch nur Ansatzweise durch hart hingeschriebene Bedingungen erfüllt?

Kreativität ist in der OO scheinbar nicht gern gesehen^^ => Unflexibiltät^^
Nein. Völlig unsinnigen und unwartbaren Code schreiben, der jeden Anforderungen völlig zuwider läuft, ist überall nicht gern gesehen. ;)
Einem Motor die Pin für irgendeinen Raum geben, ist eine ziemlich schwachsinnige Anforderung, die ist überall Unsinn.

Also ich hätte da wirklich mal Lust mit dir zu skypen. Die öffentliche Diskussion hier und mal ne private mit Dir schließen sich ja nicht gegenseitig aus.
Abgesehen von meiner Skype-Abneigung gern :p
 

knotenpunkt

Mitglied
hey,

ich melde mich aus meinem Winterschlaf zurück.

Da ja jetzt wirklich schon etwas Zeit seit den letzten Beiträgen hier vergangen ist, weiß ich nicht, ob ich den Anschluss mit 100%iger Perfektion schaffe, aber ich versuchs. Ich war in letzter Zeit uni-technisch etwas eingespannt und hatte so kaum bis hin zu 0 Zeit^^



Die Änderung der Zugriffe wird nur durch Änderung der Tupel eingerichtet.
Ich habe doch eine Datenbank erwähnt. Wo ist da jetzt der Unterschied?



hast du wie in deinem Eröffnungsthread wieder nur behauptet, Polymorphie sei nicht OOP. Und wie in deinem Eröffnungsthread hast du auch jetzt wieder offen gelassen, was du damit meinst. Mein Verständnisproblem habe ich einfach und deutlich beschrieben. Du willst es offensichtlich nicht aufklären.
Polymorphie ist doch für sich definiert: Vielgestaltigkeit
Das kann ich überall verwenden, wofür ich es angemessen halte. Seis in der OO, PP, oder sonst wo.

Nein. In deinen Beispielen wird alles zur Compilezeit entschieden. Es gibt nur die n Fälle, die zur Compilezeit ausprogrammiert sind. Welche davon bei einer Programmausführung durchlaufen werden, wird zwar erst zur Laufzeit entschieden, aber es können nur diese n Fälle sein. Das ist ein wesentlicher Unterschied zu echter Polymorphie.

Streng genommen ist auch ein einfacher Funktionsaufruf polymorph, sollte er je nach Eingabeparameter ein anderes Ergebnis zurückliefern. Ob ich jetzt eine alogrithmische Polymorphie, eine über Funktionspointer realisierte Polymorphie oder eine über Interfaces implementierte Polymorphie habe, ist egal: Alles davon ist Polymorph. Dabei ist aus performence-Gründen erst-genannte aber die sinnvollste. C++ Enthusiasten, versuchen VTABLES also virtuelle Methoden zu vermeiden; eben genau die, die für die dynamische Polymorphie notwendig sind.


Ich habe das Template-Pattern überhaupt nicht verwendet, sondern das Strategie-Muster. Es geht hier um den Algorithmus in der main-Methode, der (abgesehen von der für das schlichte Beispiel primitiv gehaltenen Objekterzeugung) nie wieder geändert werden muß, unabhängig davon, ob andere Tierarten oder anderes Bewegungsverhalten hinzu kommt oder sich etwas daran ändert. Und ja: es kann sein, das zur Implementierung des konkreten Verhaltens hier und da auch if-Abfragen verwendet werden. Das ist ja nicht verboten, wenn es sachgerecht ist. Den Algorithmus in main() geht das aber nichts an.
Das kann ich in der PP genauso machen: Eine entsprechende Dispatcher-Procedur und die Sache ist entkoppelt.




So aber nochmal um das klar zu Stellen: Mir geht es hier nicht um die Polymorphie. Auch ich selbst verwende gerne mal den ein oder anderen Funktionspointer. Und die Polymorphie in der OO ist auch nicht mein Problem. Wie ich in früheren Beiträgen bereits geschrieben habe sind folgende Punkte meine Probleme mit der OO: Kopplung von Daten und Verhalten. Vor allem aus dem Grund, weil das oftmals nicht gelingt. Und dass das oftmals nicht gelingt, zeigen doch die ganzen Service- in einem später noch verlinkten Beitrag die Doer-Klassen. Und all diese Klassen werden mittels DI miteinander verbunden.

Edit: ok ich verlinke den Beitrag am besten gleich hier: https://medium.com/@brianwill/object-oriented-programming-a-personal-disaster-1b044c2383ab


Wenn du mal konkret wirst, kann man vielleicht auch konkret darauf antworten. So kann man nur sagen, dass das Admin-Objekt, die Tatsache, dass der usertype2="IRGENDWAS" ist, eben entsprechend behandeln muß. Vielleicht tatsächlich mittels einer Verzweigung, vielleicht auch anders - jedenfalls auf eine Weise, die den Aufrufer nichts angeht, damit der sich nicht auch noch darum kümmern muss.
Und genau hier wird es interessant. Den Aufrufer interessiert es sehr wohl, ob USER =="ADMIN".
Wie würdest du folgendes machen?

Usecase: Banfunktionalität.

Und zwar eine Funktionalität, die ich nicht in die Userklassen integrieren möchte. In meiner nächsten Anwendung soll es diese Funktionalität gar nicht geben. Und so würde ich nur unnötig Funktionalität in die Userklasse binden. (1. Problem)

(2. Problem) die Banfunktion, wie sie ausgeführt werden darf und ob hängt von mehreren Parametern ab. Und zwar von
USER==ADMIN UND Uhrzeit==zwischen 12 Uhr und 14 Uhr und ZUBANNENDERUSER<ADMIN UND zig weiteren Parameter

Die eben genannte Bedinung prüft erstmal das OB und dann kommt noch das WIE, also wie lange darf der User, der Admin ist, jemanden banen; auch hier gibt es wieder viele weitere Parameter

=> Service-Klasse, die diese Funktionalität anbietet. Und in dieser muss ich jetzt sehr wohl überprüfen ob user==admin und ob zuBannenderUser<admin, um nur mal diese Beispiele zu nennen.

Und schon hat sich die Polymorphie auf schnittstellenebene erledigt.
Oder nicht? - Zeige mir etwas Gegenteiliges^^


Unabhängig davon, ob deine Aussage stimmt, ist das hier völlig irrelevant. Es ist doch offensichtlich, dass das in meinem Beispiel und auch in den meisten Büchern oder anderen Beispielen nur stellvertretend für die eigentliche Methodenimplementierung steht. Das kann doch wohl unmöglich ernsthaft das Niveau sein, auf dem du diskutieren willst.
Das hier schließt sich dem eben erwähnten nahtlos an. System.out.println(....) ist ein trivialer Fall. Im komplexeren ist das so nicht mehr realisierbar. Ist ja schön wenn eine Stockente etwas anderes auf die Konsole printet als eine Quackente (vgl. Gang of Four Buch). Aber wenn die Funktionalität mit mehreren Objekten interferiert, dann wird das so nicht mehr funktionieren.

Ähnlich dazu auch meine Funktionalität aus dem in diesem Beitrag hier früher erwähnten Beispiel der Post-Policy:

Ich weiß zwar jetzt nicht mehr genau wer es war, aber der Begriff Post-Policy wurde von jemanden von euch eingeführt, der versuchte das Chatposten in eine austauschbare Strategie zu packen. Aber genau hier haben wir das gleiche Problem: Wie möchtet ihr einen Algorithmus verstrategisieren, der von x-parametern abhängt und dazu sein volles Potential erst dann entfalten kann, wenn die entsprechender Programmcode ausgeführt wird. Heißt auch hier soll bzw. kann die Post-Policy erst zur Laufzeit und zwar direkt bei Ausführung dieser Programmstelle entscheiden, welches Ergebnis diese zurückgegeben soll oder welche andere Proceduren ausgehend von der Post-Policy-Procedur aufgerufen werden sollen.
Aber vllt. hat hierzu ja auch jemand eine passende Idee.



ist Polymorphie. Nicht so, wie man es aus Java kennt, aber trotzdem Polymorphie.
VERWENDEN Polymorphie bzw. bauen auf Polymorphie auf.


Nein, in der Regel ist davon auszugehen, dass Objekte einen möglichst kleinen Scope & Lebenszyklus haben. (Keine Ahnung, was du immer mit Konfiguriert meinst...)
Das musste mir etwas näher erklären. Aber wie bereits von mir geschrieben: Ist es doch sinnvoller statt create obj, fill obj, action() obj, delete obj folgendes zu machen: action(fill_parameter)

mit "Konfigurierst" meine ich langlebige vor allem über DI konfigurierte Strukturen. Service-Klassen werden ja oftmals anhand eines Konfigurationsfile einmalig bei Programmstart konfiguriert, und das wars. (Die Service-Klassen an sich zeigen ja schon, dass eigentlich procedural programmiert wird. Verhalten und Daten sind hier getrennt. Diesen Ansatz finde ich in Teilen gut (naja ich finde procedural eben gut^^), nur das ist eben keine Objektorientierung mehr im Sinne von Daten und Verhalten sind gekapselt.)

* Objektkonfiguration, DI, etc pp wird im Idealfall möglichst spät entschieden ("so spät wie möglich, so früh wie nötig").
* "deine flexible Programmierung" wird zur Compilezeit festgelegt. Die genauen Bedingungen schreibst du in den Code, und diese Bedingungen sind die ganze Laufzeit über fest und werden sich niemals ändern.

Naja bei meiner Banfunktionalität wird das Verhalten tatsächlich erst dann entschieden, wenn ich die Funktion ausführe. Nicht vorher schon. Das ist der spätmöglichste Zeitpunkt; früher ist hier nicht notwendig

Einem Motor die Pin für irgendeinen Raum geben, ist eine ziemlich schwachsinnige Anforderung, die ist überall Unsinn.
... aber kreativ. Und ich möchte mit meinen Programmen alles abbilden können und nicht nur das, was eben durch ein verfehltes Programmierpardigma möglich ist.


Abgesehen von meiner Skype-Abneigung gern :p
Ich habe dich schon von längerer Zeit hier im Forum privat angeschrieben, ob du nicht Lust hättest zu discorden^^
Nur leider bekam ich bislang keine Antwort; vermutlich ist meine Anfrage untergegangen.

Ich würde tatsächlich mal mit dir discorden oder skypen oder whatevern (such du dir was aus^^), vllt. lassen sich so schon einige Fragen klären. Ich habe dir jetzt nochmal geschrieben, vllt. steht es so ja wieder etwas weiter oben^^


lg knotenpunkt
 

mrBrown

Super-Moderator
Mitarbeiter
mit "Konfigurierst" meine ich langlebige vor allem über DI konfigurierte Strukturen. Service-Klassen werden ja oftmals anhand eines Konfigurationsfile einmalig bei Programmstart konfiguriert, und das wars. (Die Service-Klassen an sich zeigen ja schon, dass eigentlich procedural programmiert wird. Verhalten und Daten sind hier getrennt. Diesen Ansatz finde ich in Teilen gut (naja ich finde procedural eben gut^^), nur das ist eben keine Objektorientierung mehr im Sinne von Daten und Verhalten sind gekapselt.)
Services nutzt man, wenn man Daten und Verhalten nicht sinnvoll miteinander kapseln kann. Das das nicht immer möglich ist, stört niemanden der OO programmiert.
Das Argument ist auf der Ebene von "Autos sind scheiße und völlig unbrauchbar, damit mann man nicht mal den Mount Everest hochklettern. Nichts anderes als zu Fuß gehen ist sinnvoll."

Auch Services müssen nicht zur Startzeit konfiguriert werden - ganz im Gegenteil. Man kann auch völlig problemlos alle Services erst zur Benutzung (und bei jeder Benutzung neu) initialisieren, mit der dann existierenden "Konfiguration", die völlig dynamisch sein kann.

Naja bei meiner Banfunktionalität wird das Verhalten tatsächlich erst dann entschieden, wenn ich die Funktion ausführe. Nicht vorher schon. Das ist der spätmöglichste Zeitpunkt; früher ist hier nicht notwendig

Nein, das Verhalten ist zur Kompilezeit festgelegt. Zur Kompilezeit schreibst du deinen Algorithmus, und damit ist das Verhalten eindeutig festgelegt.
Ein Lichtschalter ist auch nicht Flexibel und das Verhalten wird erst beim drücken festgelegt - sondern das Verhalten steht bei der Verkabelung fest. Ob du den auf "ein" oder "aus" stellst, ändert nicht das Verhalten des Lichtschalters.

Zeig doch mal, wie eine (einfache und realistische beispielhafte) Banfunktionalität bei dir aussehen würde? uU kann man das mit einem Beispiel besser vergleichen.
Irgendwo schwirrt ja noch der andere Thread dazu hier rum...

... aber kreativ. Und ich möchte mit meinen Programmen alles abbilden können und nicht nur das, was eben durch ein verfehltes Programmierpardigma möglich ist.
Du kannst auch mit OO alles abbilden, wenn du es entsprechend designest. Natürlich landet man dann am Ende bei "globalem" State, wenn die Anforderung von Anfang an ist, dass alles auf einen globalen State zugreifen können soll. In den meisten Systemen braucht man das aber nicht.

Üblicherweise versucht man, etwas sinnvoll zu designen, sodass zB die Domäne sinnvoll abgebildet wird und für Fachexperten einfach verständlich ist, und dann braucht kein Motoradmotor mehr die Pin für den Banktresor.

Ich habe dich schon von längerer Zeit hier im Forum privat angeschrieben, ob du nicht Lust hättest zu discorden^^
Nur leider bekam ich bislang keine Antwort; vermutlich ist meine Anfrage untergegangen.

Ich würde tatsächlich mal mit dir discorden oder skypen oder whatevern (such du dir was aus^^), vllt. lassen sich so schon einige Fragen klären. Ich habe dir jetzt nochmal geschrieben, vllt. steht es so ja wieder etwas weiter oben^^
Ist wirklich untergegangen, ich guck gleich mal ;)
 

knotenpunkt

Mitglied
hey,

Services nutzt man, wenn man Daten und Verhalten nicht sinnvoll miteinander kapseln kann. Das das nicht immer möglich ist, stört niemanden der OO programmiert.
Das Argument ist auf der Ebene von "Autos sind scheiße und völlig unbrauchbar, damit mann man nicht mal den Mount Everest hochklettern. Nichts anderes als zu Fuß gehen ist sinnvoll."

Auch Services müssen nicht zur Startzeit konfiguriert werden - ganz im Gegenteil. Man kann auch völlig problemlos alle Services erst zur Benutzung (und bei jeder Benutzung neu) initialisieren, mit der dann existierenden "Konfiguration", die völlig dynamisch sein kann.
Aber ist das nicht der Hauptteil der Funktionalität, also Proceduren (Service-Klassen sind ja nichts anders) über Daten, die sich nicht mit einem ihrem direkt zugehörigen Verhalten kombinieren lassen?

Ok an der Stelle müssen wir glaube ich nochmal etwas genauer auf das Wort "Konfigurieren" eingehen.

Die Konfiguration die hier stattfindet ist doch in der Regel eine Art Konfiguration, die länger bestand hat. Anhand des von dir in deinem Beitrag im folgenden angesprochenem Lichtschalters kann ich diese Problematik ganz gut zeigen.

Du verwendest den Lichtschalter einmal als Deckenlampeneinschalter und ein anderes mal als Fußbodenheizungeinschalter.

Das Verhalten kannst du vorab konfigurieren und austauschen - bspw. über ein Taster der sich neben dem Lichtschalter befindet.

Um auf derartiges Austauschen verzichten zu können, könnte ich entsprechende Logik auch indirekt im Lichtschalter und Taster verbauen -> Service-Klasse Lampen/Heizung-EinschalterManager. Während der Lichtschalter nach wie vor den Befehl ein()/aus() sendet, wird dieser Befehl nicht mehr an ein polymorphes Objekt weitergeleitet, das entweder die Deckenlampe oder die Fußbodenheizung einschaltet, sondern an den Manager, der dann live zur Laufzeit entscheidet auch in Abhängigkeit des Tasters vllt. nach der Uhrzeit und noch einigen weiteren Parametern, ob der Fußboden oder die Deckenlampe aktiviert werden sollen. So bin ich doch gleich mal viel flexibler unterwegs.




Zeig doch mal, wie eine (einfache und realistische beispielhafte) Banfunktionalität bei dir aussehen würde? uU kann man das mit einem Beispiel besser vergleichen.
Irgendwo schwirrt ja noch der andere Thread dazu hier rum...

//*II
ban_user(WER,WEN,wievielUhrHabenWirgerade, weitereParameter)
{
if(.......)//ob überhaupt
{
if(......)/wie
{

}
else
{

}

// *I

}
}

Interessant wird das ganze zudem dann, wenn ich das ganze um eine Benachrichtigungsoption erweitern möchte; dazu habe ich jetzt mehrere Möglichkeiten.

Mgl 1: in die ban_user funktion integrieren und zwar an der Stelle *I. notifyUser(WEN)

Mgl 2: davor und zwar mit ban_user2 die dann die eigentliche ban_user funktion aufruft, das ergebnis abwartet und dann entsprechend notified, übrigens in abhängigkeit dessen, wie WEN seine Benachrichtungseinstellungen gewählt hat UND ob das WIE in ban_user eine benachrichtigung überhaupt vorsieht und vllt. noch anhand weiterer Parameter. An der Stelle *II hätte das ganze den Vorteil, dass ich hier unabhängig von der Benachrichtigungsfunktion bin

Aber das soll hier jetzt nur nebensächlich sein.


Du kannst auch mit OO alles abbilden, wenn du es entsprechend designest. Natürlich landet man dann am Ende bei "globalem" State, wenn die Anforderung von Anfang an ist, dass alles auf einen globalen State zugreifen können soll. In den meisten Systemen braucht man das aber nicht.

Üblicherweise versucht man, etwas sinnvoll zu designen, sodass zB die Domäne sinnvoll abgebildet wird und für Fachexperten einfach verständlich ist, und dann braucht kein Motoradmotor mehr die Pin für den Banktresor.

Naja als globalen State würde ich das hier jetzt noch nicht ansehen:
Während der Motoradmotor sich für die Pin des Banktresors interessiert, interessiert sich dieser noch lange nicht für irgendwelche Internas meiner Netzwerkimplementierung.


Aber meistens ist es doch so, wenn ich ne Klasse A habe, dass diese sich sehr wohl für ein paar internas anderer Klassen, auch wenn nicht alle, interessiert.


Klassisches Beispiel:

Class Mensch
Class Arm
Class Hand
Class Finger
Class Fingernagel

Eine GUI die den Menschen grafisch darstellen soll, interessiert sich sehr wohl für alle internas des Menschen, oder für eine Facade des Menschen, das alle internas in einer flachgeklopften Schnittstelle anbietet, also ein haufen redundanter Methodenaurufe, wobei Class Mensch die meisten Methoden hat, die ihrerseits an weiter unter liegender Schicht deligieren.


Ein weiteres Beispiel hierzu: Class Mensch soll die Methode isKrank() haben. Um das bestimmen zu können muss sie bspw. auf den Fingernagel zugreifen, übrigens keine direkte Klassenabhängigkeit Mensch <-> Fingernagel. Ist das Fingerbeet entzündet so ist der Mensch zu einem gewissen Faktor krank. Außerdem muss Class Mensch auf die Umwelt zugreifen, um die Körpertemperatur mit dieser vergleichen zu können. Wie genau würdest du jetzt auf das Fingerbeet und auf die Umwelt von Class Mensch zugreifen, oder würdest du eine Service Klasse schreiben die den Krankheitszustand des Menschen D bestimmt.
Weil: Vllt. muss die Service Klasse auch noch überprüfen, wie sich andere Menschen in der geografischen Lage des Menschen D fühlen um den Krankheitszustand von D genau bestimmen zu können.

Wie gesagt triviale Probleme kann ich lokal lösen und hier dann auch super toll polymorphie über den Mechanismus Interface nutzen. Aber die Probleme sind nicht trivial und zwar spätesten dann nicht wenn ich irgendwas erweitern möchte. Warum sollte ich mich von vornherein einschränken, nur um dann im Refactoringprozess alles über den Haufen werfen zu müssen, was dann eh wieder im proceduralen endet?

Ist wirklich untergegangen, ich guck gleich mal ;)
Hast dus' bereits gefunden?^^


lg knotenpunkt


PS: ich glaube so schnell habe ich noch nie geantwortet^^
 

mrBrown

Super-Moderator
Mitarbeiter
Aber ist das nicht der Hauptteil der Funktionalität, also Proceduren (Service-Klassen sind ja nichts anders) über Daten, die sich nicht mit einem ihrem direkt zugehörigen Verhalten kombinieren lassen?
Nein, das kommt gänzlich auf die Domäne an. Es gibt durchaus einige Fälle, in denen man das ganze Verhalten in Entitäten und Aggregaten (in DDD-Sprache) abbilden kann, und keine Services braucht.

Wobei das natürlich drauf an kommt, wo man die Grenze zwischen Service und nicht-Service zieht. Wenn man da auch so Dinge wie Controller, Repositorys und ähnliches drin sieht, kommt man natürlich nicht ohne Services aus - ich würde die aber klar davon getrennt sehen.



Du verwendest den Lichtschalter einmal als Deckenlampeneinschalter und ein anderes mal als Fußbodenheizungeinschalter.

Das Verhalten kannst du vorab konfigurieren und austauschen - bspw. über ein Taster der sich neben dem Lichtschalter befindet.

Um auf derartiges Austauschen verzichten zu können, könnte ich entsprechende Logik auch indirekt im Lichtschalter und Taster verbauen -> Service-Klasse Lampen/Heizung-EinschalterManager. Während der Lichtschalter nach wie vor den Befehl ein()/aus() sendet, wird dieser Befehl nicht mehr an ein polymorphes Objekt weitergeleitet, das entweder die Deckenlampe oder die Fußbodenheizung einschaltet, sondern an den Manager, der dann live zur Laufzeit entscheidet auch in Abhängigkeit des Tasters vllt. nach der Uhrzeit und noch einigen weiteren Parametern, ob der Fußboden oder die Deckenlampe aktiviert werden sollen. So bin ich doch gleich mal viel flexibler unterwegs.
In OO würde man, statt der Service-Klasse, ein Delegate- oder Proxy-Objekt verwenden. Das kann genau das gleiche, wie deine Manager-Methode, nur eben zusätzlich noch State halten.
Das ganze in einem zustandslosen Service zu machen, hat als Nachtei tendenziell die Zustandslosigkeit, einen Vorteil sehe ich da nicht. (Man kann jetzt natürlich auch den Proxy als Service bezeichnen, würde ich aber als falsch ansehen.)


//*II
ban_user(WER,WEN,wievielUhrHabenWirgerade, weitereParameter)
{
if(.......)//ob überhaupt
{
if(......)/wie
{

}
else
{

}

// *I

}
}
Die interessanten Dinge sind leider leer gelassen, mit ein paar ausformulierten Bedingung könnte man da deutlich besser was zu sagen ;)

Einfach mal beispielhaft von mir deshalb: if (idBefore12PM(wievielUhrHabenWirgerade) && isAdmin(WER) && isNoAdmin(WEN))

Das Problem dabei ist, die Bedingungen sind einmal festgelegt, und danach nicht änderbar. Angenommen, das ganze läuft jetzt als Web-Plattform, und ab jetzt sollen Admins auch andere Admins bannen können, dann muss der Code geändert werden, und das ganze neu kompiliert und deployed werden. Will also der "Foren-Admin" die Einstellung ändern, muss er Programmiere und System-Admin um die Änderung bitten.


In OO könnte das ganze so aussehen:

Code:
BanConditions conditions;

ban_user(WER,WEN,wievielUhrHabenWirgerade, weitereParameter)
{
if(conditions.allMatch(WER,WEN,wievielUhrHabenWirgerade, weitereParameter)) //ob überhaupt
....
und zb
Code:
TimeCondition implements BanCondition {
    TimeRange range;
    test(WER,WEN,wievielUhrHabenWirgerade, weitereParameter) {
        return wievielUhrHabenWirgerade.isIn(range);
    }
}

Will man das jetzt neu konfigurieren, ändert man einfach die Liste der Conditions oder ändert einzelne Conditions.
Um, wie oben, auch Admins bannen zu können, nimmt man einfach den Check raus, der Testet ob der gebannte Admin ist. Völlig Problemlos zur Laufzeit möglich. Und, was mit zB Java auch möglich wäre, man könnte gänzlich neue Conditions zur Laufzeit nachladen.

Interessant wird das ganze zudem dann, wenn ich das ganze um eine Benachrichtigungsoption erweitern möchte; dazu habe ich jetzt mehrere Möglichkeiten.

Mgl 1: in die ban_user funktion integrieren und zwar an der Stelle *I. notifyUser(WEN)

Mgl 2: davor und zwar mit ban_user2 die dann die eigentliche ban_user funktion aufruft, das ergebnis abwartet und dann entsprechend notified, übrigens in abhängigkeit dessen, wie WEN seine Benachrichtungseinstellungen gewählt hat UND ob das WIE in ban_user eine benachrichtigung überhaupt vorsieht und vllt. noch anhand weiterer Parameter. An der Stelle *II hätte das ganze den Vorteil, dass ich hier unabhängig von der Benachrichtigungsfunktion bin
Nicht anders wäre das mit OO möglich, einen Proxy drum, der, ähnlich wie das Bannen selbst, prüft, ob eine Nachricht versendet werden soll.
Vorteil ist wieder die einfache Umkonfiguration zur Laufzeit, ohne das der relevante Code dafür angepasst werden muss.

Eine GUI die den Menschen grafisch darstellen soll, interessiert sich sehr wohl für alle internas des Menschen, oder für eine Facade des Menschen, das alle internas in einer flachgeklopften Schnittstelle anbietet, also ein haufen redundanter Methodenaurufe, wobei Class Mensch die meisten Methoden hat, die ihrerseits an weiter unter liegender Schicht deligieren.

Je - eine GUI, die Interna darstellen soll, muss irgendwie an diese Interna kommen. Genaus braucht eine Fassade, die alle Interna darstellen soll, zugriff auf die Interna...das sind aber beides Spezialfälle, die man durchaus auch lösen kann, ohne alles direkt nach außen zu geben ("Tell, dont ask").

Ein weiteres Beispiel hierzu: Class Mensch soll die Methode isKrank() haben. Um das bestimmen zu können muss sie bspw. auf den Fingernagel zugreifen, übrigens keine direkte Klassenabhängigkeit Mensch <-> Fingernagel. Ist das Fingerbeet entzündet so ist der Mensch zu einem gewissen Faktor krank. Außerdem muss Class Mensch auf die Umwelt zugreifen, um die Körpertemperatur mit dieser vergleichen zu können. Wie genau würdest du jetzt auf das Fingerbeet und auf die Umwelt von Class Mensch zugreifen, oder würdest du eine Service Klasse schreiben die den Krankheitszustand des Menschen D bestimmt.
Weil: Vllt. muss die Service Klasse auch noch überprüfen, wie sich andere Menschen in der geografischen Lage des Menschen D fühlen um den Krankheitszustand von D genau bestimmen zu können.

Das Checken des Krankheitszustands: Mensch fragt alle direkten Körperteile, ob sie gesund sind, in diesem Fall ist der Arm relevant. Der Arm macht dann das gleiche mit seinen Teilen, Hand das gleiche, bis hin zum Fingernagel. Der kann dann eine Entzündung zurückgeben. Ziemlich einfach lösbar, ohne Service.

Für die anderen beiden nutzt man je nach Design durchaus Services. Aus genau dem Punkt, den ich auch schon nannte: Sowohl die Umwelt drum herum als auch andere Menschen betreffen nicht mehr den einen Mensch, sondern andere, fremde Entitäten - und Dinge, die mehrere unterschiedliche Entitäten betreffen, sind Aufgaben von Services.

Wie gesagt triviale Probleme kann ich lokal lösen und hier dann auch super toll polymorphie über den Mechanismus Interface nutzen. Aber die Probleme sind nicht trivial und zwar spätesten dann nicht wenn ich irgendwas erweitern möchte. Warum sollte ich mich von vornherein einschränken, nur um dann im Refactoringprozess alles über den Haufen werfen zu müssen, was dann eh wieder im proceduralen endet?
Die meisten Dinge sind so lösbar. Ich stand bisher noch nie vor dem Punkt, dass ich dache, dass Prozentual an der Stelle besser gewesen wäre...

Natürlich klappt das nicht ohne Refactoring, wenn die Anforderungen am Ende völlig gegensätzlich zu den Ursprünglichen sind, aber das erwartet ehrlich gesagt auch niemand. Das gleiche Problem hat man in jeder Sprache, völlig unabhängig vom Paradigma.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
K Modellierung Chat-Server (von OO ist gescheitert) Softwareentwicklung 14

Ähnliche Java Themen

Neue Themen


Oben