OO ist gescheitert

Diskutiere OO ist gescheitert im Softwareentwicklung Bereich.

Ist OO (definiert nach Alan Key) gescheitert?

  • JA

  • NEIN


Die Ergebnisse sind erst nach der Abstimmung einsehbar.
A

AndiE

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.
 
K

knotenpunkt

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

mrBrown

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

mrBrown

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

mihe7

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.
 
A

AndiE

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?
 
M

Meniskusschaden

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());
    }
}
 
K

knotenpunkt

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
 
A

AndiE

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.
 
M

Meniskusschaden

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

mihe7

@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? :)
 
M

Meniskusschaden

@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

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

mrBrown

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
 
K

knotenpunkt

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

mrBrown

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 ;)
 
K

knotenpunkt

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

mrBrown

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.
 
Thema: 

OO ist gescheitert

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben