# OO ist gescheitert



## knotenpunkt (15. Mai 2018)

in dem Thread möchte ich nur zwei Punkte ansprechen, die darlegen warum oo vllt. nicht so sinnvoll ist.

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.
Dabei ist wichtig, dass Daten und Verhalten gekapselt wird.

Klassen, die im Namen Service/Manager/Sachbearbeiter etc pp haben sind Prozedurensammlungen, die zwar in sich selbst oobjektorientiert konfiguriert werden können, dann aber auf den DomänenObjekten, also den eigentlichen Daten/Entitäten, prozedural arbeiten. Diese werden in die Services hineingereicht, herausgereicht, herumgereicht, so wie man es eben aus der prozeuduralen Programmierung kennt.

Viele Programmierprojekte verwenden diese Service-Klassen.
Ein Indiz dafür ist der Gebrauch der DI-Injektion/Service-Lokatoren.

Ein objektorientiertes Softwareprojekt würde keine einzige DI-Injektion benötigen.

Warum aber verwenden viele DI-Injektionen/Service-Klassen.
Vllt. einfach aus dem Grund, weil OO nichts taugt?!
Wie seht ihr das?


Jetzt hätte ich mal noch eine Frage zu einem OO-Aufbau, wie ihr das selbst/anders machen würdet.
Ich habe eine normale oder aber auch Service Klasse, die wie folgt aussehen könnte.


```
class Blub
{
public T member1;
public T member2;
public T member3;

public T member4

public Blub(......)
{
....
}

public RESULT doSth(T arg1, T arg2)
{
// und das ganze macht irgendwas //und verwendet member1-3 sowie arg1-2
}


}
```

die Probleme, die ich mit dem ganzen hier habe sind die Folgende.

1:
nach welchem sinnvollen Algorithmus soll ich entscheiden, dass member1-3 fest in das Objekt gebunden sind und arg1-2 schön dynamisch hineingereicht werden können/dürfen?

2:
möchte ich die Methode/Message-Empfänger doSth mit unterschiedlichen member1-3 variablen aufrufen, so habe ich zwei möglichkeiten:
Ich habe ein Objekt vom Typ Blub und vor jedem doSth Aufruf passe ich member1-3 an.
Oder ich erstelle N Objekte vom Typ Blub und rufe hier jeweils doSth auf.
Fühlt sich beides sehr falsch an^^
Ein BSP:

Ich habe eine EmailServiceKlasse, die zur Aufgabe hat, DomänenObjekte mit dem Typ EmailNachricht (enthält Absender, Betreff, Empfänger) überreicht zu bekommen und schließlich mit den in dem Service hinterlegten Config-Daten, die Email abzusenden. 
Die DomänenObjekte vom Typ EmailNachricht sind anemic (siehe Fowler), da sie einer c++ Struct ohne nennenswertes Verhalten gleichen. Also ich finde die Structs gut, Fowler findet sie im Kontext der objektorientierung nicht gut. 
Die Service-Klasse EmailServiceKlasse dagen ist in sich selbst schon OO aufgebaut. 
Man kann Sie bspw. mit dem Emailanbieter konfigurieren. Also Domain, Port, Sonstiges.
Ausserdem erhält die EmailServiceKlasse eine Abhängigkeit LoggerServiceKlasse1 eingespritzt. 

Was ist aber, wenn ich jetzt bspw. zur Laufzeit in Abhängigkeit von Uhrzeit und von der EmailNachricht (Typ EmailNaricht) bestimmen möchte, dass ich LoggerServiceKlasse2 oder LoggerServiceKlasse7 verwenden möchte? Außerdem habe ich 50Emailanbieter und auch das soll genau wie die LoggerServiceKlassen zur Laufzeit und in Abhängigkeit........ entschieden werden.

Ich glaube Ihr seht das Problem, oder?

Eine einfache prozedur mit 

```
sendMail(Emailnachricht)
{
//hole in Abhängigkeit von time() und Emailnachricht -> LoggerServiceKlasseX
//hole in Abhängikeit von time() und Emailnachricht ->EmailanbieterX

sendMail(LoggerServiceKlasseX, EmailanbieterX, Emailnachricht)//überladen

}
```
wäre doch viel besser.

pseudo-OO mit einer weiteren ServiceKlasse könnte dann wie folgt aussehen:


```
class EmailanbieterANDLoggerServiceDeciderService
{

public sendMail(Emailnachricht)
{
extrahiere aus Emailnachricht und time() -> LoggerServiceKlasseX und EmailanbieterDataX

new EmailService(LoggerServiceX, EmailanbieterDataX).sendMail(Emailnachricht);

}

}
```
Nein wir haben nicht den 1. April, aber so wird das teilweise gemacht.
Den Sinn dahinter verstehe ich nicht^^

Und jetzt möchte ich noch ein Newsletter an 1Mio User senden.
Warum soll ich mir 1Mio*(was ich sonst noch an unnötiigen over-head-Klassen habe) sinnlose Objekte auf meinen wertvollen HEAP-Speicher klatschen, nur um eine prozedurale-Funktionalität auszuführen?


3:
member4 wird in doSth gar nicht benötigt, in doSthOthers() vllt. dann schon.
Das ganze Kollidiert auch mit (2
Wenn ich dann ständig 

```
new EmailService(LoggerServiceX, EmailanbieterDataX, null).sendMail(Emailnachricht);
//wobei null member4 abdeckt
```
aufurufen muss, dann ist der Mond bereits mit der Erde zu einem Saturn2 fusioniert^^

Das Single-Responsibilty-Prinzip decke ich am besten in einer Prozedur ab. 
Eine Prozedur benötigt genau exakt die Daten, die es für sich eben benötigt.
Eine MemberFunktion die den This-Pointer/This-Referenz bekommt, davon aber nur 20% der enthaltenen Daten benötigt, hat nur unnötige Abhängigkeiten.


Soweit erstmal, ich habe noch einiges mehr, was OO den Nährstoff entziehen würde, aber ich belasse es erstmal dabei.

Und wie oben bereits geschrieben. Eine Archtitektur mit an Haufen Service-Klassen, die mit anemic-DomänObjekten/Structs arbeiten ist nicht objektorientiert, sondern wie ich es an der Stelle gerne nenne: Pseudo-objektorientiert. Die ServiceKlassen-Landschaft selbst ist objektorientiert. Das Zusammenspiel mit den Daten, mit denen die Landschaft arbeitet dagegen nicht. Zumindest ein Schritt in die richtige Richtung. Wenn jetzt auch die Landschaft selbst wieder proezduraler werden würde -> dann hätten wir endlich wieder eine sehr gute Codequalität, die einerseits performant ist, andererseits aufgrund Ihrer Einfachheit und nicht Overheadheit gut wartbar ist und dritterseits wesentlich schneller zum Erfolg führt.



lg knotenpunkt


----------



## mrBrown (16. Mai 2018)

knotenpunkt hat gesagt.:


> ```
> class Blub
> {
> public T member1;
> ...


Kommt drauf an, ob man mehr als nur "Alles ist ein Objekt und die kommunizieren über Messages" für die Beantwortung zulassen will 

Sind halt Design/Entwurfs-Fragen, die kann man eben auch nur auf Design-Ebene klären - und dann landet man bei sowas wie SOLID, High Cohesion, der Domäne...

Nur mit den oben stehenden Informationen: völlig egal was man macht.




knotenpunkt hat gesagt.:


> 2:
> möchte ich die Methode/Message-Empfänger doSth mit unterschiedlichen member1-3 variablen aufrufen, so habe ich zwei möglichkeiten:
> Ich habe ein Objekt vom Typ Blub und vor jedem doSth Aufruf passe ich member1-3 an.
> Oder ich erstelle N Objekte vom Typ Blub und rufe hier jeweils doSth auf.
> Fühlt sich beides sehr falsch an^^



Die erste Variante ist Unsinn - wäre das nötig, sollten die Dinge Argumente und keinen Felder sein.
Variante zwei ist völlig Plausibel: wenn member1-3 Teil des Objekts sind, sind's mit unterschiedlichen member1-3 unterschiedliche Objekte, warum sollte ich sie dann nicht neu erzeugen?

Mit nur so spärlichen Informationen kann man da aber keine fundierte Aussage treffen...



knotenpunkt hat gesagt.:


> Was ist aber, wenn ich jetzt bspw. zur Laufzeit in Abhängigkeit von Uhrzeit und von der EmailNachricht (Typ EmailNaricht) bestimmen möchte, dass ich LoggerServiceKlasse2 oder LoggerServiceKlasse7 verwenden möchte? Außerdem habe ich 50Emailanbieter und auch das soll genau wie die LoggerServiceKlassen zur Laufzeit und in Abhängigkeit........ entschieden werden.
> 
> Ich glaube Ihr seht das Problem, oder?


Hm, einfach für beides einen Proxy.
Der EmailService braucht davon keine Ahnung zu haben, der ruft einfach die entsprechenden Methoden auf (auf dem Proxy, der das entsprechend weiter delegiert).




knotenpunkt hat gesagt.:


> Und jetzt möchte ich noch ein Newsletter an 1Mio User senden.
> Warum soll ich mir 1Mio*(was ich sonst noch an unnötiigen over-head-Klassen habe) sinnlose Objekte auf meinen wertvollen HEAP-Speicher klatschen, nur um eine prozedurale-Funktionalität auszuführen?


Du kannst dir die nötigen Informationen natürlich auf den noch wertvolleren Stack-Speicher klatschen 
Irgendwo müssen die nötigen Informationen liegen, wie soll man sie sonst versenden?



knotenpunkt hat gesagt.:


> member4 wird in doSth gar nicht benötigt, in doSthOthers() vllt. dann schon.
> Das ganze Kollidiert auch mit (2
> Wenn ich dann ständig
> 
> ...



Deshalb würde man es auch nicht so machen, eine mögliche Lösung steht weiter oben...



knotenpunkt hat gesagt.:


> Das Single-Responsibilty-Prinzip decke ich am besten in einer Prozedur ab.
> Eine Prozedur benötigt genau exakt die Daten, die es für sich eben benötigt.
> Eine MemberFunktion die den This-Pointer/This-Referenz bekommt, davon aber nur 20% der enthaltenen Daten benötigt, hat nur unnötige Abhängigkeiten.



Das Single-Responsibilty-Prinzip decke ich am besten mit mehreren Klassen/Objekten ab. 
Ein Objekt besteht genau exakt den Daten, die es für sich eben benötigt.
Einer Prozedur alle nötigen Daten einzeln übergeben, ist doch völliger Unsinn 




knotenpunkt hat gesagt.:


> Und wie oben bereits geschrieben. Eine Archtitektur mit an Haufen Service-Klassen, die mit anemic-DomänObjekten/Structs arbeiten ist nicht objektorientiert, sondern wie ich es an der Stelle gerne nenne: Pseudo-objektorientiert. Die ServiceKlassen-Landschaft selbst ist objektorientiert. Das Zusammenspiel mit den Daten, mit denen die Landschaft arbeitet dagegen nicht.


Deswegen nutzt man ja auch kein anemic-model, sondern ein vernünftiges Domain-Model. Fowler dazu: "The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design".
Das ist etwas, was ich gerne Pseudo-Argument nenne  Ein Argument, was PRO gutem-OO benutzt wird, so verdrehen, dass man das als KONTRA OO nutzen kann.



knotenpunkt hat gesagt.:


> Wenn jetzt auch die Landschaft selbst wieder proezduraler werden würde -> dann hätten wir endlich wieder eine sehr gute Codequalität, die einerseits performant ist, andererseits aufgrund Ihrer Einfachheit und nicht Overheadheit gut wartbar ist und dritterseits wesentlich schneller zum Erfolg führt.



Also wieder alles zurück auf Anfang, damit man dann von dort aus von neuem den Vorteil von Objekt-Orientiertem Design sehen kann?


----------



## knotenpunkt (16. Mai 2018)

Hey,



mrBrown hat gesagt.:


> Nur mit den oben stehenden Informationen: völlig egal was man macht.


Ich suche eben eine generische Lösung. Ein statisch aufgebautes starres objekorientiertes Programmgerüst, ist nicht wirklich flexibel und generisch einsetzbar. Das hat zur Folge das es gut testbar ist, aber auch dass man viel Code für wenig Funktionalität schreibt.



mrBrown hat gesagt.:


> Die erste Variante ist Unsinn - wäre das nötig, sollten die Dinge Argumente und keinen Felder sein.
> Variante zwei ist völlig Plausibel: wenn member1-3 Teil des Objekts sind, sind's mit unterschiedlichen member1-3 unterschiedliche Objekte, warum sollte ich sie dann nicht neu erzeugen?


Wenn ich jetzt im Batch-Betrieb doSth aufrufen möchte?
Die Objektinstanzen sind in dem Fall nur kurzlebig, also eine Art ProzedurenObjekt. new Object() -> parameter als Membervariablen via set-Methoden setzen -> executeMethod aurufen -> Destructor/Garbage Collection.

Eine direkte Prozedurenaufruf wäre erstens ressourcenschonender und würde nicht soviel Overhead-Code benötigen.



mrBrown hat gesagt.:


> Das Single-Responsibilty-Prinzip decke ich am besten mit mehreren Klassen/Objekten ab.
> Ein Objekt besteht genau exakt den Daten, die es für sich eben benötigt.
> Einer Prozedur alle nötigen Daten einzeln übergeben, ist doch völliger Unsinn


Warum ist das Unsinn?
So hast du  die Möglichkeit, wirklich alles aus der Prozedur rauszuholen. Bspw. indem du den übergebenen State leicht abändern kannst, nur für die Prozedur.
Zudem kannst du der Prozedur Structs (c++), associative Arrays (PHP), Java-Objekte ohne Verhalten == structs wie in C/C++ übergeben. Somit übergibst die Variablen auch gesammelt^^. Zudem hast du die Möglichkeit mehrere gesammelte Daten zu übergeben und nicht nur ein Datensammelsatz (this).
Desweiteren können die Structs bei Bedarf vor der Übergabe angepasst werden.
Arbeite ich dann nur mit dem Rückgabewert weiter bin ich schon fast bei der funktionalen programmierung angelagant. Mit einem Sideffekt bin ich dann bei der prozeduralen Programmierung.

Aber warum ist das nicht sinnvoll?



mrBrown hat gesagt.:


> Hm, einfach für beides einen Proxy.
> Der EmailService braucht davon keine Ahnung zu haben, der ruft einfach die entsprechenden Methoden auf (auf dem Proxy, der das entsprechend weiter delegiert).


Könntest du eventuell ein Beispiel posten. Kann mir nicht ganz vorstellen was du meinst.
Aber ich denke es fällt auch hier ein prozedural aufgebautes Programm heraus.



mrBrown hat gesagt.:


> Du kannst dir die nötigen Informationen natürlich auf den noch wertvolleren Stack-Speicher klatschen
> Irgendwo müssen die nötigen Informationen liegen, wie soll man sie sonst versenden?


Ist denke so bin ich ressourcenschonender und zweitens auch flexibler.
Du kannst die Programmstruktur auch für Third-Party APIs gut einsetzen, wo du die Daten nicht selbst im Speicher hälst. Auch passt das ganze perfekt zu relationelen Datenbanken, wo du die Datenänderungen direkt auf/in der Datenbank durchführst.



mrBrown hat gesagt.:


> Deshalb würde man es auch nicht so machen, eine mögliche Lösung steht weiter oben...


Was würde man so nicht machen?



mrBrown hat gesagt.:


> Deswegen nutzt man ja auch kein anemic-model, sondern ein vernünftiges Domain-Model. Fowler dazu: "The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design".
> Das ist etwas, was ich gerne Pseudo-Argument nenne  Ein Argument, was PRO gutem-OO benutzt wird, so verdrehen, dass man das als KONTRA OO nutzen kann.


Wie sieht ein vernünftiges und vor allem flexibles und dynamisch einsetzbares domain-model aus?
Du hast noch nichts zu meinen oben genannten Services und DI-Injection/Service-Locatoren gesagt.
In einem vernünftigen Domain-Model kommen diese nicht vor, würdest du das bestätigen?
Wenn aber keine proezdurale Service-Klassen existieren, wie erreichst du dann ein dynamisches Programm? auf der Grundlage von einer starren/unflexiblen Objektwelt?
Ich denke die Paradoxie erkennt man^^

Ein Beispiel, was ich dafür immer gerne hernehme:

Du möchtest eine UserBan-Funktionalität implementieren.
Es macht null Sinn, die Banfunktionalität in die Klasse eines Users/Admin hineinzuimplementieren.
Also benötige ich hier sozusagen einen BanService, etwas aussenstehendes

diesem BanService wird jetzt folgendes übergeben. der User der bannen möchte, der User der gebannt werden soll, die Uhrzeit und vieles weitere (eventuell holt sich die Funktion die Daten auch selbst, da noch zu Beginn nicht ganz klar ist, welche Daten die Funktion letzten Endes benötigt)

Gehen wir davon aus der bannende User hat die abstrakte Adminberechtigung 5
Alle Admins mit dem Status 5 dürfen nur zwischen 17 und 18Uhr bannen. 

Außerdem gibt der Admin eine Ban-Zeit zwischen 1-10 an.

Wählt der Admin die 4 und hat davor schon 3User gebannt, die älter als 70Jahre sind und eine weitere Person die sich erst vor 3Tagen registriert hat, dann beträgt bei der Nummer vier die Ban-Zeit der aktuellen Person 9 Tage. Außerdem, sollte die zu bannende Person bereits über 6Monate registriert sein, wird diese via Email über den Ban benachrichtigt. Je nach Flags, die der Admin setzt, kann die Emailbenachrichtigung unterdrückt und falls nicht, im Detail angepasst werden.

usw. usf.

Warum das ganze nicht in die UserAdmin-Klasse?
Vllt. möchte das System selbst ohne zutun eines Admins selbst auch User bannen können, aufgrund irgendwelcher Kriterien. 


Was ich damit verdeutlichen möchte: Das ganze geht doch nur sinnvoll in einer Prozedur bzw. divide-and-conquer Prozedurlandschaft.
Wie möchtest du das sinnvoll objektorientiert machen?




mrBrown hat gesagt.:


> Also wieder alles zurück auf Anfang, damit man dann von dort aus von neuem den Vorteil von Objekt-Orientiertem Design sehen kann?


Zurück auf ein Level, das gut funktioniert.
Man sollte nicht OO Programmieren des OO zu Willen.

Und warum verwenden soviele Programmierer Services/etc pp?
Services sind prozedural!


lg knotenpunkt


----------



## mrBrown (16. Mai 2018)

knotenpunkt hat gesagt.:


> Ich suche eben eine generische Lösung. Ein statisch aufgebautes starres objekorientiertes Programmgerüst, ist nicht wirklich flexibel und generisch einsetzbar. Das hat zur Folge das es gut testbar ist, aber auch dass man viel Code für wenig Funktionalität schreibt.


Häh? ich habe keine Ahnung, was das mit Objektorientiert vs Prozedual zu tun hat...



knotenpunkt hat gesagt.:


> Wenn ich jetzt im Batch-Betrieb doSth aufrufen möchte?
> Die Objektinstanzen sind in dem Fall nur kurzlebig, also eine Art ProzedurenObjekt. new Object() -> parameter als Membervariablen via set-Methoden setzen -> executeMethod aurufen -> Destructor/Garbage Collection.
> 
> Eine direkte Prozedurenaufruf wäre erstens ressourcenschonender und würde nicht soviel Overhead-Code benötigen.



Objektorientiert != Garbagecollector != Resourcen-Verschwendend != Overhead-Code.

Nach dem Kompilieren kann aus "new Object() -> parameter als Membervariablen via set-Methoden setzen -> executeMethod aurufen -> Destructor/Garbage Collection." durchaus ein "executeMethod aurufen" geworden sein, genauso wie das bei deiner Variante der Fall wäre.

Ressourcenschonender ist dann nichts mehr, es bleibt der "Overhead-Code" (solange du das "mehr" an nötigem Source-Code meinst), der von den wenigstens als "Overhead" angesehen wird, sondern einfach als sinnvolle Struktur.




knotenpunkt hat gesagt.:


> Warum ist das Unsinn?
> So hast du die Möglichkeit, wirklich alles aus der Prozedur rauszuholen. Bspw. indem du den übergebenen State leicht abändern kannst, nur für die Prozedur.
> Zudem kannst du der Prozedur Structs (c++), associative Arrays (PHP), Java-Objekte ohne Verhalten == structs wie in C/C++ übergeben. Somit übergibst die Variablen auch gesammelt^^. Zudem hast du die Möglichkeit mehrere gesammelte Daten zu übergeben und nicht nur ein Datensammelsatz (this).
> Desweiteren können die Structs bei Bedarf vor der Übergabe angepasst werden.
> ...



Und bringe ich dann die Funktion noch mit in dem Objekt unter, sodass ich die Funktion und die dazu gehörenden Daten zusammen habe, bin ich bei Objektorientiert und wir drehen uns im Kreis.
Und Vermeide ich dann Seiteneffekte, bin ich bei Objektorientiert und Funktional (siehe Scala).

Wenn du Objekte bei Objektorientierter Programmierung als "Datensammelsatz" ansiehst, hast du Objektorientierte Programmierung nicht verstanden - dann ist es natürlich besser, keine Objektorientierte Programmierung zu nutzen.




knotenpunkt hat gesagt.:


> Könntest du eventuell ein Beispiel posten. Kann mir nicht ganz vorstellen was du meinst.
> Aber ich denke es fällt auch hier ein prozedural aufgebautes Programm heraus.



Wenn du über Objektorientierte Programmierung urteilen willst, sollte dir doch zumindest das Proxy-Pattern geläufig sein?


```
class MailService{
  sendMail(Mail mail) {
    mailLogger.log(mail);
    mailServer.send(mail);
  }
}
interface  MailLogger {
  log(Mail mail);
}
class MailLoggerProxy implements MailLogger {
 log(Mail mail) {
   MailLogger logger  = getLoggerForMail(mail);
    logger.log(mail);
  }

  getLoggerForMail(Mail mail) {
    //die von dir nicht gezeigte Magie...
  }
}
class SimpleMailLogger implements MailLogger {
 log(Mail mail) {
   sout(mail.sender);
  }
}
```
 
Aber wie erreichst du denn bei deinem rein prozeduralem Programm zB die Auswahl zwischen unterschiedlichen Mail-Servern, die auf unterschiedliche Arten und Weisen benutzt werden müssen? Und wie kann man da dynamisch zur Laufzeit neue hinzufügen?




knotenpunkt hat gesagt.:


> Ist denke so bin ich ressourcenschonender und zweitens auch flexibler.
> Du kannst die Programmstruktur auch für Third-Party APIs gut einsetzen, wo du die Daten nicht selbst im Speicher hälst. Auch passt das ganze perfekt zu relationelen Datenbanken, wo du die Datenänderungen direkt auf/in der Datenbank durchführst.


Inwiefern sind Daten auf dem Stack resourcenschonender und flexibler als auf dem Heap? (wobei Objektorientiert natürlich nicht voraussetzt, das Daten überhaupt auf dem Heap liegen, da vermischt du wieder eine Mögliche Implementierung mit einem Konzept)
Und wie bringst du überhaupt 1 Mio. Mails auf dem Stack unter?

Wo die Daten herkommen ist völlig egal, ich kann durchaus auch Objektorientiert mit denen arbeiten, wenn die in einer Relationen Datenbank liegen.
Wie passt deine Lösung eigentlich zu Objektorientierten Datenbanken? 




knotenpunkt hat gesagt.:


> Was würde man so nicht machen?


Das, was ich zitiert hab?



knotenpunkt hat gesagt.:


> Wie sieht ein vernünftiges und vor allem flexibles und dynamisch einsetzbares domain-model aus?



Genauso, wie die eine "vernünftige und vor allem flexible und dynamisch einsetzbare" Prozedur aussieht: nicht existent.

Ein Domänen-Modell ist nur ein Modell für *eine* Domäne, wie soll sowas dynamisch und flexibel aussehen?


knotenpunkt hat gesagt.:


> Du hast noch nichts zu meinen oben genannten Services und DI-Injection/Service-Locatoren gesagt.
> In einem vernünftigen Domain-Model kommen diese nicht vor, würdest du das bestätigen?
> Wenn aber keine proezdurale Service-Klassen existieren, wie erreichst du dann ein dynamisches Programm? auf der Grundlage von einer starren/unflexiblen Objektwelt?
> Ich denke die Paradoxie erkennt man^^



Weder kommen Service-Klassen in einem Domänen-Model niemals vor, noch sind diese zwingend nötig. (Der Begriff "Service" ist btw. hauptsächlich durch *Domain-Driven-Design* geprägt.)

Ich habe keine Ahnung, was du unter einem "dynamischen Programm" verstehst, aber generell und nach deiner Definition von OO erreicht man das, indem Objekte sich Nachrichten schicken.

DI ist aber ein generelles Konzept, und hat nicht mit Services zu tun.
Es ist nichts weiter, als dass Objekte ihre Abhängigkeiten übergeben bekommen, anstatt sie sich selbst zu besorgen. Über die Abhängigkeiten sagt das nichts aus.




knotenpunkt hat gesagt.:


> Ein Beispiel, was ich dafür immer gerne hernehme:
> [...]
> Was ich damit verdeutlichen möchte: Das ganze geht doch nur sinnvoll in einer Prozedur bzw. divide-and-conquer Prozedurlandschaft.
> Wie möchtest du das sinnvoll objektorientiert machen?



Dein Argument ist: Sobald irgendwo eine Funktion existiert, ist das ganze Prozedural und absolut nicht mehr Objekt-Orientiert?

Wie würdest du das ganze denn, ohne jegliche Objekt-Orientierung, umsetzen? Ellenlange Methoden mit zig verschachtelten if's?




knotenpunkt hat gesagt.:


> Zurück auf ein Level, das gut funktioniert.
> Man sollte nicht OO Programmieren des OO zu Willen.
> 
> Und warum verwenden soviele Programmierer Services/etc pp?
> Services sind prozedural!



Man programmiert nicht OO, um OO zu programmieren, sondern weil es für die meisten Dinge gut Funktioniert. OO gibt es nicht ohne Grund.

Und das Methoden in Services Prozedural sind (ich gehe mal davon aus, dass das nach deiner Definition von Prozedural so ist), bedeutet für dich, dass sie nicht mehr Objektorientiert sind?


----------



## AndiE (16. Mai 2018)

Als "Halb-Laie" finde ich den Titel sehr provokativ, und auch der Entscheidung, was OOP ist und was nicht, kann ich nicht zustimmen. 
Aus meiner "C"-Zeit kenne ich das so, dass Maschinencode (Mnemotics) in Prozeduren zusammengefaßt wurden, und es dann Header-Dateien mit den Signaturen gab und Compilierte Bibliotheken. Das Programm selbst besteht dann wieder das Prozeduren, die Porzeduren aufrufen, wobei mit der "main()"-Prozedur begonnen wird. In diesem Umfeld, dass ich als "prozedural" bezeichnen würde, gibt es dann als komplexisten Typen die "struct", die mehrere Daten verschiedener Typen zusammenfasst.
 Der objektorientierte Ansatz, wie wir ihn aus dem MVC- oder dem 3-Schichten-Modell kennen, erzeugt Datenobjekte, die miteinander kommunizieren. Dabei kann man eben zwischen der statischen und der dynamischen Sicht unterscheiden. Bei einem Taschenrechner gibt es eine Klasse, die die Darstellung übernimmt und Nutzereingaben entgegennimmt. Bei einer Nutzereingabe ruft sie eine Methode des Controllers auf, der wiederum eine Methode des Datenobjektes aufruft. So würde ich das organisieren, auch wenn es hier im Forum gerne anders gemacht wird. Der Vorteil ist eben, dass ich als Bearbeiter mich nicht erst umständlich in das reindenken muss, was der andere programmiert hat.Wer schon mal den Hüpfweg in einem prozeduralen Programm nachvollzogen hat, weiß was ich meine. Bei einer CD-Verwaltung etc. kann ich die vorhandene Struktur im Datenmodell realitätsnah abbilden. Ich habe ein Regal->ich bilde das mit einer List-Klasse ab. In dem Regal sind CD->Datenobjekte. 

Ich finde, dass Scriptsprachen dazu verleiten, dieses Paradigma zu umgehen, was dann zu "IOP-indirekt objektorientierter Programmierung" führt, ein Begriff, der mir im Zusammenhang mit "Perl" aufgefallen ist. Dabei benutzt man die Methoden der "vorgefertigten" Klassen, und das Programm selbst kommt ohne Klassendefinition und Methodendeklaration aus.


----------



## knotenpunkt (17. Mai 2018)

mrBrown hat gesagt.:


> Häh? ich habe keine Ahnung, was das mit Objektorientiert vs Prozedual zu tun hat...


Es soll einen negativen Gesichtspunkt von OO hervorheben und gleichzeitig darauf hinweisen, dass Prozedurale Programmierung diese Schwäche nicht hat.




mrBrown hat gesagt.:


> Objektorientiert != Garbagecollector != Resourcen-Verschwendend != Overhead-Code.
> 
> Nach dem Kompilieren kann aus "new Object() -> parameter als Membervariablen via set-Methoden setzen -> executeMethod aurufen -> Destructor/Garbage Collection." durchaus ein "executeMethod aurufen" geworden sein, genauso wie das bei deiner Variante der Fall wäre.
> 
> Ressourcenschonender ist dann nichts mehr, es bleibt der "Overhead-Code" (solange du das "mehr" an nötigem Source-Code meinst), der von den wenigstens als "Overhead" angesehen wird, sondern einfach als sinnvolle Struktur.


Es kann?!...... Ja die Compiler optimieren schon ganz gut, wobei ob das hier wegoptimiert wird, das ist so die Frage^^
Aber es fühlt sich halt einfach schlecht an, "schlechten" Code zu schreiben, auch wenn der Compiler das nacher wegoptimieren würde. Warum nicht gleich straightforward programmieren?
Ja ich meine mit Overhead auch den Source-Code.
Warum soll diese Struktur, die du meinst, sinnvoller sein?
Es sieht vllt. ästhetisch aus, mehr aber auch nicht. Und wenn man dann noch weiß, dass dies wegoptimiert werden muss, dass es performt, dann sehe ich darin auch keine Ästhetik mehr^^




mrBrown hat gesagt.:


> Und bringe ich dann die Funktion noch mit in dem Objekt unter, sodass ich die Funktion und die dazu gehörenden Daten zusammen habe, bin ich bei Objektorientiert und wir drehen uns im Kreis.
> Und Vermeide ich dann Seiteneffekte, bin ich bei Objektorientiert und Funktional (siehe Scala).
> 
> Wenn du Objekte bei Objektorientierter Programmierung als "Datensammelsatz" ansiehst, hast du Objektorientierte Programmierung nicht verstanden - dann ist es natürlich besser, keine Objektorientierte Programmierung zu nutzen.


Diese Seiteneffekte sind unter Umständen ja gewollt. Ok vermutlich nicht für denjenigen, der den Code dann testen soll. Aber sinnvoll strukturiert, kann man auch beherrschbaren prozeduralen Code schreiben.

Möchte ich Funktionen und Daten zusammen in ein Objekt bringen, dann bedingt das ganze auch, dass die Daten vor Ort sind. So sind direkte Datenmanipulationen direkt auf der Datenbank bspw. ausgeschlossen.
Zudem, wann arbeitet eine Objektmethode auch nur auf den Daten, die sie selbst bereithält?
Es gibt einen Fall, wo das so ist: ADTs und einfachste Datentypen......... but that was it.

Folgende Probleme tauchen bei komplexeren Datenstrukturen auf.
Erstens möchte ich nicht lange Graphoperationen durchführen um an irgend ein Objekt/Datensatz im letzten Zweig des grossen Urwalds zu kommen und zweitens möchte ich vllt. auch gar keinen Graphen haben, sondern schön losgekoppelte Objekte/Daten.

Zum Thema "OOP als \"Datensammelsatz\"":
Nein ich sehe das nicht so. Aber genau weil ich das nicht so sehe, sehe ich OO als gescheitert an^^
Wann macht es deiner Meinung nach Sinn Funktionen an die Daten zu knüpfen. 
Meiner Meinung nach - wie oben geschrieben - bei ADTS (Listen,.....) und einfachsten Datentypen (boolean, int) (also Datentypen, wo die Funktionen auch wirklich nur auf dem Datentyp arbeitet).



mrBrown hat gesagt.:


> Wenn du über Objektorientierte Programmierung urteilen willst, sollte dir doch zumindest das Proxy-Pattern geläufig sein?


Ich kenne sogar alle GoF-Patterns und weitere + Architekturpatterns



mrBrown hat gesagt.:


> Aber wie erreichst du denn bei deinem rein prozeduralem Programm zB die Auswahl zwischen unterschiedlichen Mail-Servern, die auf unterschiedliche Arten und Weisen benutzt werden müssen? Und wie kann man da dynamisch zur Laufzeit neue hinzufügen?


Die liegen alle vor: Als Datensatz direkt im Programmcode oder auch in der Datenbank.
Das witzige an deinem Codebeispiel ist eben, dass es meiner Meinung nach prozedural arbeitet.

Dein Mailserver (1Funktion -> 1Prozedur) ruft weitere Subprozeduren (-> loggger und sendMail).
Diese sind eben in weiteren Prozedurenklassen hinterlegt.
Ich sehe hier keinen Vorteil.
Welchen Vorteil siehst du darin?...... Das sind weitestgehend stateless Prozedurenklassen, die keiner Klasse bedürften. 

Aber auch ein anderers Problem sehe ich hier. Ein Problem, das ich auch ganz generell in der prozeduralen Programmierung habe, wenn ich den Code auf verschiedene Funktionen aufteile, wenn auch nicht ganz so drastisch.

Gehen wir mal davon aus, zur Bestimmung des Log-Services, aber auch zur Bestimmung des Emailanbieters wird ein ähnlicher Code ausgeführt. Was ich meine ist das. Ein berechnetes Zwischenergebnis beim Finden des LogServices kann dazu hergenommen werden, den Emailanbieter zu bestimmen. Trenne ich das so strikt, wie du es gemacht hast, so kann ich ein temporär berechnetes Zwischenergebnis dafür nicht hernehmen. Und das kann ganz sicher kein Compiler wegoptimieren.

prozedural würde ich das dann so ähnlich machen. sendMail(mailData) -> calculate LogService(mailData)
aus dem LogService kommen jetzt zwei Datensäze zurück, einerseits der LogService an sich und zweitens irgend ein beschleunigendes Zwischenergebnis tmpData

Also rufe ich jetzt ne prozedur auf, die wie folgt heisst: ->calculate Emailanbieter (mailData, tmpData)
Im Falle dessen, dass mir tmpData nicht zur Verfügung steht, weil ich bspw. auf den LogService verzichtet habe, schreibe ich natürlich auch noch einfach ein calculateEmailanbieter(struct mailData) Prozedur

Wie würdest du das objektorientierisieren?
Und warum würdest du das überhaupt mit 5 veschiedenen Klassen machen, wenn es doch auch straightforward geht, in java also mit static functionen. 

Und wie gehst du an die Sache heran, wenn du es Top-Bottom oder Bottom-Up aufbaust?
Wie sind deine Gedankengänge, das direkt von Anfang an richtig zu machen?





mrBrown hat gesagt.:


> Inwiefern sind Daten auf dem Stack resourcenschonender und flexibler als auf dem Heap? (wobei Objektorientiert natürlich nicht voraussetzt, das Daten überhaupt auf dem Heap liegen, da vermischt du wieder eine Mögliche Implementierung mit einem Konzept)
> Und wie bringst du überhaupt 1 Mio. Mails auf dem Stack unter?
> 
> Wo die Daten herkommen ist völlig egal, ich kann durchaus auch Objektorientiert mit denen arbeiten, wenn die in einer Relationen Datenbank liegen.
> Wie passt deine Lösung eigentlich zu Objektorientierten Datenbanken?


Ja in C++ kann ich sie mir auch auf den Stack oder sonst wohin packen. War wirklich etwas falsch von mir formuliert.

Wenn die Daten in der Datenbank liegen, dann kann ich sie erstmal durch umständliche OR-Mapper oder händisch in meinen Speicher holen und dabei schön nen Graphen aufbauen und dann damit arbeiten -> das finde ich nicht ressourcenschonend.

Andererseits kann ich wieder meine prozeduren/Service-Klassen verwenden, die dann direkt mit der DatenbankAPI kommunizieren....... Das ist meiner Meinung nach sinnvoll, da ich mir hier vor allem schnell arbeitende Datenbanken zu Nutze machen kann. 



mrBrown hat gesagt.:


> Das, was ich zitiert hab?


Die Problemstellung war die, dass unter Umständen unnötige Abhängikeiten in der Doing/prozeduren/Service-Klasse habe, die für bestimmte Methodenaurufe irrelevant sind und somit störend!



mrBrown hat gesagt.:


> Genauso, wie die eine "vernünftige und vor allem flexible und dynamisch einsetzbare" Prozedur aussieht: nicht existent.
> 
> Ein Domänen-Modell ist nur ein Modell für *eine* Domäne, wie soll sowas dynamisch und flexibel aussehen?


Das musste mir etwas näher erklären^^




mrBrown hat gesagt.:


> Weder kommen Service-Klassen in einem Domänen-Model niemals vor, noch sind diese zwingend nötig. (Der Begriff "Service" ist btw. hauptsächlich durch *Domain-Driven-Design* geprägt.)
> 
> Ich habe keine Ahnung, was du unter einem "dynamischen Programm" verstehst, aber generell und nach deiner Definition von OO erreicht man das, indem Objekte sich Nachrichten schicken.
> 
> ...


Nach Fowler sollten sie auch nicht vorkommen. Und ich sehe das genau wie Fowler, objektorientierung besteht nicht aus service-Klasssen. Der Einsatz dieser Klassen macht das ganze wieder prozedural mit oo-ästhetik. Nur dass es dann icht vielleicht sogar besser wäre auf diese Ästhetik zu verzichten und direkt prozedural (das schließt eine Modualisierung nicht aus!) zu programmieren.

Ja Objekte schicken sich Nachrichten, aber was steht deiner Meinung nach in diesen Narchrichten drinnen. 
In deiner MailService Klasse wird ein MailObjekt/Struct geschickt........... prozeduren schicken sich auch derartige Nachrichten. Wie sollen sich die Nachrichten bei ordentlicher oo-programmierung unterscheiden?

Was ich vor allem als undynamisch ansehe ist das folgende:
Die festverdrahteten Objekte. Die Membervariablen, die fest verdrahtet auf andere Objekte zeigen. 
Somit habe ich eine Möglichkeit um an diese Informationen zu kommen, aus der Sichtweise einer Prozedur oder Service-Klasse:

Ich muss mich mich im Graph entlang hangeln bis ich an entsprechender Information bin, die aber in sich dann ein anemic Objekt darstellt. 

ein Datenbanksystem dagegen kann das viel effizienter und ich komme direkt an die Information.

Wenn ich jetzt aus den Anemic-Objekten richtige Objekte mache, sprich funktionalität dazuimplementiere, dann arbeitet die funktionalität auf THIS, also auf den Daten des Objekts selbst. Und das macht das ganze unflexibel, da ich ja nur auf den THIS Daten arbeiten darf/kann.
Also werden unabhängige Serviceklassen/prozeduren eingeführt um in die ganze Bude wieder etwas Schwung/dynamic zu bringen^^




mrBrown hat gesagt.:


> Dein Argument ist: Sobald irgendwo eine Funktion existiert, ist das ganze Prozedural und absolut nicht mehr Objekt-Orientiert?
> 
> Wie würdest du das ganze denn, ohne jegliche Objekt-Orientierung, umsetzen? Ellenlange Methoden mit zig verschachtelten if's?


Divide-And-Conquer...... also viele Methoden/Funktionen. 
Switch-Cases finde ich gar nicht so problematisch. Aber wenn es sein muss, kann man auch schön polymorphe Funktionspointer einsetzen^^
Zum Thema "wenn irgendwo eine Funktion existiert": Ja das ist ein Schritt weg von OO. Nicht gänzlich, aber kein reines OO mehr. Je mehr -> desto mehr pseudo-oo wird es^^



mrBrown hat gesagt.:


> Man programmiert nicht OO, um OO zu programmieren, sondern weil es für die meisten Dinge gut Funktioniert. OO gibt es nicht ohne Grund.
> 
> Und das Methoden in Services Prozedural sind (ich gehe mal davon aus, dass das nach deiner Definition von Prozedural so ist), bedeutet für dich, dass sie nicht mehr Objektorientiert sind?


Warum und für was funktioniert es gut?

Ja es ist nicht mehr objektorientiert. 
Und die Frage, die ich mir stelle, warum dann überhaupt Service-Klassen und nicht direkt Service-prozeduren.
Auch diese kann man konfigurieren.
Aber das ist nicht das Hauptthema.
Das Hauptthema ist die Frage, warum verwenden soviele Programmierer, wenn Sie meinen OO zu programmieren, ServiceKlassen. 
Meiner Meinung nach, weil Sie das reine OO nicht akzeptieren und das somit ein klares Indiz, dass es gescheitert ist.


@AndiE 

Gegen Datenmodellierung habe ich nichts.
Mich stört es nur Funktionalität und Daten zusammenzupacken.
Und anscheinend stört das nicht nur mich, sondern viele andere auch -> Lösung, wenn auch nur bedingt sinnvoll: Serviceklassen.
Das andere was du ansprichst, sind Architekturentscheidungen, die erstmal nichts mit OO zu tun haben. 
ich kann auch MVC ohne Klassen und Objekte programmieren^^
Das ist nur ne Frage der Modularisierung/Strukturierens.

OO ist eine Frage des ProgrammierDenkens.

MVC lässt sich sowohl im oo-denken als auch im pp-denken umsetzen.

Und wenn du die einzelnen patterns aus mvc herausarbeiten möchtest, bspw. strategy und observer, dann geht das sehr gut mit prozeduralem Denken. Wie ich oben geschrieben habe, kannst du ja für die polymorphie (auf polymorphie bauen die ganzen DesignPatterns ja auf) Funktionspointer verwenden, oder auch switch-cases, die super schnell sind.

in C++ sollte man wo es nur geht auf vtables verzichten. 


Ja gut soweit


lg knotenpunkt


----------



## Meniskusschaden (17. Mai 2018)

knotenpunkt hat gesagt.:


> Wie ich oben geschrieben habe, kannst du ja für die polymorphie (auf polymorphie bauen die ganzen DesignPatterns ja auf) Funktionspointer verwenden


Das ist eben der gängige Weg, objektorientiertes Design umzusetzen, wenn man nur eine prozedurale Sprache hat. Ist wohl eher ein Argument pro OO.


----------



## mrBrown (18. Mai 2018)

knotenpunkt hat gesagt.:


> Es soll einen negativen Gesichtspunkt von OO hervorheben und gleichzeitig darauf hinweisen, dass Prozedurale Programmierung diese Schwäche nicht hat.


Du kannst also rein prozedural ein "flexibel und generisch einsetzbares Programmgerüst" schreiben?




knotenpunkt hat gesagt.:


> Aber es fühlt sich halt einfach schlecht an, "schlechten" Code zu schreiben, auch wenn der Compiler das nacher wegoptimieren würde. Warum nicht gleich straightforward programmieren?


Für mich fühlt es sich besser an, klaren und verständlichen Code zu schreiben, anstatt hochoptimierten...



knotenpunkt hat gesagt.:


> Es sieht vllt. ästhetisch aus


"ästhetisch aussehen" im Sinne von "klar, verständlich, strukturiert, etc" (was Lesbarkeit, Wartbarkeit und Testbarkeit impliziert) ist zumindest mir deutlich wichtiger als performant und Maschinennah...




knotenpunkt hat gesagt.:


> Zudem, wann arbeitet eine Objektmethode auch nur auf den Daten, die sie selbst bereithält?
> Es gibt einen Fall, wo das so ist: ADTs und einfachste Datentypen......... but that was it.


Nö, eigentlich ist das in den meisten vernünftigen, Domänenorientierten Entwürfen der Fall.




knotenpunkt hat gesagt.:


> Erstens möchte ich nicht lange Graphoperationen durchführen um an irgend ein Objekt/Datensatz im letzten Zweig des grossen Urwalds zu kommen und zweitens möchte ich vllt. auch gar keinen Graphen haben, sondern schön losgekoppelte Objekte/Daten.


Beides kannst du mit vernünftigem Design verhindern.



knotenpunkt hat gesagt.:


> Zum Thema "OOP als \"Datensammelsatz\"":
> Nein ich sehe das nicht so. Aber genau weil ich das nicht so sehe, sehe ich OO als gescheitert an^^
> Wann macht es deiner Meinung nach Sinn Funktionen an die Daten zu knüpfen.
> Meiner Meinung nach - wie oben geschrieben - bei ADTS (Listen,.....) und einfachsten Datentypen (boolean, int) (also Datentypen, wo die Funktionen auch wirklich nur auf dem Datentyp arbeitet).


Viellicht solltest du dich mal tiefergehend mit Objekt-Orientiertem Design beschäftigen? Grundlektüre wäre da Domain Driven Design.



knotenpunkt hat gesagt.:


> Die liegen alle vor: Als Datensatz direkt im Programmcode oder auch in der Datenbank.
> Das witzige an deinem Codebeispiel ist eben, dass es meiner Meinung nach prozedural arbeitet.
> 
> Dein Mailserver (1Funktion -> 1Prozedur) ruft weitere Subprozeduren (-> loggger und sendMail).
> ...



Na gut, ich seh's ein: wenn man geschachtelte Objekte, die über Messages kommunizieren, als prozedural bezeichnet, programmieren alle prozedural.

Nur so als Frage: was ist für dich Objektorientiert, wenn es über Messages kommunizierende Objekte nicht sind?




knotenpunkt hat gesagt.:


> Aber auch ein anderers Problem sehe ich hier. Ein Problem, das ich auch ganz generell in der prozeduralen Programmierung habe, wenn ich den Code auf verschiedene Funktionen aufteile, wenn auch nicht ganz so drastisch.
> 
> Gehen wir mal davon aus, zur Bestimmung des Log-Services, aber auch zur Bestimmung des Emailanbieters wird ein ähnlicher Code ausgeführt. Was ich meine ist das. Ein berechnetes Zwischenergebnis beim Finden des LogServices kann dazu hergenommen werden, den Emailanbieter zu bestimmen. Trenne ich das so strikt, wie du es gemacht hast, so kann ich ein temporär berechnetes Zwischenergebnis dafür nicht hernehmen. Und das kann ganz sicher kein Compiler wegoptimieren.
> 
> ...


In dem Fall, gibt es eben ein Objekte, was als Cache für das Zwischenergebnis fungiert, oder die Mail selbst kann das zurückgeben und cacht es entsprechend, alles kein Hexenwerk...

gibt zig Varianten, ohne die genauen Anforderungen zu kennen, kann man da keine von Anfang an richtige Lösung liefern - genausowenig bei der Prozeduralen Variante.

Warum ich das mit 5 Klassen machen würde?
Weil 5 Klassen, die jeweils für genau ein Ding zuständig sind, deutlich einfacher sind, als 17 Prozeduren, die jeweils 32 Dinge tun.
Prozedural habe ich immer eine extreme Bindung von allen Dingen, was das ganze extrem starr und unflexibel macht. (Um mal auf Alan Key zurückzukommen: spätes Binden ist einer der wesentlichen Punkte von OO, wenn OO gescheitert ist, dürfe spätes Binden ja auch schlecht sein?)




knotenpunkt hat gesagt.:


> Ja in C++ kann ich sie mir auch auf den Stack oder sonst wohin packen. War wirklich etwas falsch von mir formuliert.



Und wo packst du die zum Versenden nötigen Daten jetzt hin, damit sie weniger Platz als in der OO-Variante brauchen? Oder übernimmt dann die DB das verschicken, und deine Anwendung benutzt die Daten gar nicht? 



knotenpunkt hat gesagt.:


> Wenn die Daten in der Datenbank liegen, dann kann ich sie erstmal durch umständliche OR-Mapper oder händisch in meinen Speicher holen und dabei schön nen Graphen aufbauen und dann damit arbeiten -> das finde ich nicht ressourcenschonend.
> 
> Andererseits kann ich wieder meine prozeduren/Service-Klassen verwenden, die dann direkt mit der DatenbankAPI kommunizieren....... Das ist meiner Meinung nach sinnvoll, da ich mir hier vor allem schnell arbeitende Datenbanken zu Nutze machen kann.


Du wirst immer Fälle finden, für die irgendwas ungeeignet ist...

Wenn ich keinerlei Objekte brauche und auch keinerlei Business-Logik in diesen habe, dann nutz ich halt auch keine Objekt-Orientierte Sprache.
Wenn du natürlich nicht zueinander passende Sprache und Anforderungen wählst, sind solche Probleme klar...



knotenpunkt hat gesagt.:


> Das musste mir etwas näher erklären^^


Du forderst: "vernünftiges und vor allem flexibles und dynamisch einsetzbares domain-model"

Definier doch mal bitte, was deiner Meinung nach ein eben dieses ist?

Ein domain-model ist für eine spezifische Problemdomäne da - was muss da für dich flexibles und dynamisch sein?



knotenpunkt hat gesagt.:


> Nach Fowler sollten sie auch nicht vorkommen. Und ich sehe das genau wie Fowler, objektorientierung besteht nicht aus service-Klasssen. Der Einsatz dieser Klassen macht das ganze wieder prozedural mit oo-ästhetik. Nur dass es dann icht vielleicht sogar besser wäre auf diese Ästhetik zu verzichten und direkt prozedural (das schließt eine Modualisierung nicht aus!) zu programmieren.



Ein Service-Layer, welches die gesamte Business-Logik enthält, hat nichts mit OO zu tun - und eben das kritisiert Fowler!
Ein Service, ohne "-Layer", nach DDD, gehört durchaus zur Problemdomäne, auch bei Fowler. Leseempfehlung (von Fowler): Domain Driven Design.

Aus "ein kleiner Teil des Objekt-Orientierten Designs ist prozedural" ist für mich auch noch kein "besser ganz auf OO verzichten"...



knotenpunkt hat gesagt.:


> Ja Objekte schicken sich Nachrichten, aber was steht deiner Meinung nach in diesen Narchrichten drinnen.
> In deiner MailService Klasse wird ein MailObjekt/Struct geschickt........... prozeduren schicken sich auch derartige Nachrichten. Wie sollen sich die Nachrichten bei ordentlicher oo-programmierung unterscheiden?



Um mich selbst zu zitieren: "wenn man geschachtelte Objekte, die über Messages kommunizieren, als prozedural bezeichnet, programmieren alle prozedural."

Wenn für dich OO == Prozedural ist, warum führen wir dieses Gespräch eigentlich?



knotenpunkt hat gesagt.:


> Was ich vor allem als undynamisch ansehe ist das folgende:
> Die festverdrahteten Objekte. Die Membervariablen, die fest verdrahtet auf andere Objekte zeigen.
> 
> Ich muss mich mich im Graph entlang hangeln bis ich an entsprechender Information bin, die aber in sich dann ein anemic Objekt darstellt.



Gute Erkenntnis: schlecht umgesetztes OO ist schlecht. Herzlichen Glückwunsch dazu.

Sind die Argumente eigentlich bewusst nicht für sinnvolles OO zutreffend, sondern nur für Objekte als Datencontainer, die man bei Prozeduraler Programmierung üblicherweise nutzt?
*Dabei* musst du dich durch die Daten hangeln - mit OO dagegen kannst du es anders lösen (und machst das bei vernünftigem OO auch).




knotenpunkt hat gesagt.:


> Wenn ich jetzt aus den Anemic-Objekten richtige Objekte mache, sprich funktionalität dazuimplementiere, dann arbeitet die funktionalität auf THIS, also auf den Daten des Objekts selbst. Und das macht das ganze unflexibel, da ich ja nur auf den THIS Daten arbeiten darf/kann.
> Also werden unabhängige Serviceklassen/prozeduren eingeführt um in die ganze Bude wieder etwas Schwung/dynamic zu bringen^^


Und eine Prozedur kann nur auf den ihr übergebenen Daten arbeiten, ist Prozedual jetzt etwa noch stärker eingeschränkt?

Das Objekte mit sich selbst arbeiten, habe ich bisher weder als Einschränkung noch als Unflexibel  empfunden...
Ganz im Gegenteil, eine Einschränkung ist doch völlig nötig. Wie soll denn ein Entwurf, bei dem alles Zugriff auf alles hat, in irgendwer Art und Weise überschaubar bleiben?



knotenpunkt hat gesagt.:


> Das Hauptthema ist die Frage, warum verwenden soviele Programmierer, wenn Sie meinen OO zu programmieren, ServiceKlassen.
> Meiner Meinung nach, weil Sie das reine OO nicht akzeptieren und das somit ein klares Indiz, dass es gescheitert ist.



Deine Meinung, von der dich auch niemand abbringen können wird.

Meine Meinung: Prozedural ist gescheitert, weil die meisten Leute OO oder Funktional programmieren.


----------



## mrBrown (18. Mai 2018)

knotenpunkt hat gesagt.:


> Es soll einen negativen Gesichtspunkt von OO hervorheben und gleichzeitig darauf hinweisen, dass Prozedurale Programmierung diese Schwäche nicht hat.


Du kannst also rein prozedural ein "flexibel und generisch einsetzbares Programmgerüst" schreiben?




knotenpunkt hat gesagt.:


> Aber es fühlt sich halt einfach schlecht an, "schlechten" Code zu schreiben, auch wenn der Compiler das nacher wegoptimieren würde. Warum nicht gleich straightforward programmieren?


Für mich fühlt es sich besser an, klaren und verständlichen Code zu schreiben, anstatt hochoptimierten...



knotenpunkt hat gesagt.:


> Es sieht vllt. ästhetisch aus


"ästhetisch aussehen" im Sinne von "klar, verständlich, strukturiert, etc" (was Lesbarkeit, Wartbarkeit und Testbarkeit impliziert) ist zumindest mir deutlich wichtiger als performant und Maschinennah...




knotenpunkt hat gesagt.:


> Zudem, wann arbeitet eine Objektmethode auch nur auf den Daten, die sie selbst bereithält?
> Es gibt einen Fall, wo das so ist: ADTs und einfachste Datentypen......... but that was it.


Nö, eigentlich ist das in den meisten vernünftigen, Domänenorientierten Entwürfen der Fall.




knotenpunkt hat gesagt.:


> Erstens möchte ich nicht lange Graphoperationen durchführen um an irgend ein Objekt/Datensatz im letzten Zweig des grossen Urwalds zu kommen und zweitens möchte ich vllt. auch gar keinen Graphen haben, sondern schön losgekoppelte Objekte/Daten.


Beides kannst du mit vernünftigem Design verhindern.



knotenpunkt hat gesagt.:


> Zum Thema "OOP als \"Datensammelsatz\"":
> Nein ich sehe das nicht so. Aber genau weil ich das nicht so sehe, sehe ich OO als gescheitert an^^
> Wann macht es deiner Meinung nach Sinn Funktionen an die Daten zu knüpfen.
> Meiner Meinung nach - wie oben geschrieben - bei ADTS (Listen,.....) und einfachsten Datentypen (boolean, int) (also Datentypen, wo die Funktionen auch wirklich nur auf dem Datentyp arbeitet).


Viellicht solltest du dich mal tiefergehend mit Objekt-Orientiertem Design beschäftigen? Grundlektüre wäre da Domain Driven Design.



knotenpunkt hat gesagt.:


> Die liegen alle vor: Als Datensatz direkt im Programmcode oder auch in der Datenbank.
> Das witzige an deinem Codebeispiel ist eben, dass es meiner Meinung nach prozedural arbeitet.
> 
> Dein Mailserver (1Funktion -> 1Prozedur) ruft weitere Subprozeduren (-> loggger und sendMail).
> ...



Na gut, ich seh's ein: wenn man geschachtelte Objekte, die über Messages kommunizieren, als prozedural bezeichnet, programmieren alle prozedural.

Nur so als Frage: was ist für dich Objektorientiert, wenn es über Messages kommunizierende Objekte nicht sind?




knotenpunkt hat gesagt.:


> Aber auch ein anderers Problem sehe ich hier. Ein Problem, das ich auch ganz generell in der prozeduralen Programmierung habe, wenn ich den Code auf verschiedene Funktionen aufteile, wenn auch nicht ganz so drastisch.
> 
> Gehen wir mal davon aus, zur Bestimmung des Log-Services, aber auch zur Bestimmung des Emailanbieters wird ein ähnlicher Code ausgeführt. Was ich meine ist das. Ein berechnetes Zwischenergebnis beim Finden des LogServices kann dazu hergenommen werden, den Emailanbieter zu bestimmen. Trenne ich das so strikt, wie du es gemacht hast, so kann ich ein temporär berechnetes Zwischenergebnis dafür nicht hernehmen. Und das kann ganz sicher kein Compiler wegoptimieren.
> 
> ...


In dem Fall, gibt es eben ein Objekte, was als Cache für das Zwischenergebnis fungiert, oder die Mail selbst kann das zurückgeben und cacht es entsprechend, alles kein Hexenwerk...

gibt zig Varianten, ohne die genauen Anforderungen zu kennen, kann man da keine von Anfang an richtige Lösung liefern - genausowenig bei der Prozeduralen Variante.

Warum ich das mit 5 Klassen machen würde?
Weil 5 Klassen, die jeweils für genau ein Ding zuständig sind, deutlich einfacher sind, als 17 Prozeduren, die jeweils 32 Dinge tun.
Prozedural habe ich immer eine extreme Bindung von allen Dingen, was das ganze extrem starr und unflexibel macht. (Um mal auf Alan Key zurückzukommen: spätes Binden ist einer der wesentlichen Punkte von OO, wenn OO gescheitert ist, dürfe spätes Binden ja auch schlecht sein?)




knotenpunkt hat gesagt.:


> Ja in C++ kann ich sie mir auch auf den Stack oder sonst wohin packen. War wirklich etwas falsch von mir formuliert.



Und wo packst du die zum Versenden nötigen Daten jetzt hin, damit sie weniger Platz als in der OO-Variante brauchen? Oder übernimmt dann die DB das verschicken, und deine Anwendung benutzt die Daten gar nicht? 



knotenpunkt hat gesagt.:


> Wenn die Daten in der Datenbank liegen, dann kann ich sie erstmal durch umständliche OR-Mapper oder händisch in meinen Speicher holen und dabei schön nen Graphen aufbauen und dann damit arbeiten -> das finde ich nicht ressourcenschonend.
> 
> Andererseits kann ich wieder meine prozeduren/Service-Klassen verwenden, die dann direkt mit der DatenbankAPI kommunizieren....... Das ist meiner Meinung nach sinnvoll, da ich mir hier vor allem schnell arbeitende Datenbanken zu Nutze machen kann.


Du wirst immer Fälle finden, für die irgendwas ungeeignet ist...

Wenn ich keinerlei Objekte brauche und auch keinerlei Business-Logik in diesen habe, dann nutz ich halt auch keine Objekt-Orientierte Sprache.
Wenn du natürlich nicht zueinander passende Sprache und Anforderungen wählst, sind solche Probleme klar...



knotenpunkt hat gesagt.:


> Das musste mir etwas näher erklären^^


Du forderst: "vernünftiges und vor allem flexibles und dynamisch einsetzbares domain-model"

Definier doch mal bitte, was deiner Meinung nach ein eben dieses ist?

Ein domain-model ist für eine spezifische Problemdomäne da - was muss da für dich flexibles und dynamisch sein?



knotenpunkt hat gesagt.:


> Nach Fowler sollten sie auch nicht vorkommen. Und ich sehe das genau wie Fowler, objektorientierung besteht nicht aus service-Klasssen. Der Einsatz dieser Klassen macht das ganze wieder prozedural mit oo-ästhetik. Nur dass es dann icht vielleicht sogar besser wäre auf diese Ästhetik zu verzichten und direkt prozedural (das schließt eine Modualisierung nicht aus!) zu programmieren.



Ein Service-Layer, welches die gesamte Business-Logik enthält, hat nichts mit OO zu tun - und eben das kritisiert Fowler!
Ein Service, ohne "-Layer", nach DDD, ist aber eben nicht zu ersetzen und gehört durchaus zur Problemdomäne. Leseempfehlung (von Fowler): Domain Driven Design.

Aus "ein kleiner Teil des Objekt-Orientierten Designs ist prozedural" ist für mich auch noch kein "besser ganz auf OO verzichten"...



knotenpunkt hat gesagt.:


> Ja Objekte schicken sich Nachrichten, aber was steht deiner Meinung nach in diesen Narchrichten drinnen.
> In deiner MailService Klasse wird ein MailObjekt/Struct geschickt........... prozeduren schicken sich auch derartige Nachrichten. Wie sollen sich die Nachrichten bei ordentlicher oo-programmierung unterscheiden?



Um mich selbst zu zitieren: "wenn man geschachtelte Objekte, die über Messages kommunizieren, als prozedural bezeichnet, programmieren alle prozedural."

Wenn für dich OO == Prozedural ist, warum führen wir dieses Gespräch eigentlich?



knotenpunkt hat gesagt.:


> Was ich vor allem als undynamisch ansehe ist das folgende:
> Die festverdrahteten Objekte. Die Membervariablen, die fest verdrahtet auf andere Objekte zeigen.
> 
> Ich muss mich mich im Graph entlang hangeln bis ich an entsprechender Information bin, die aber in sich dann ein anemic Objekt darstellt.



Gute Erkenntnis: schlecht umgesetztes OO ist schlecht. Herzlichen Glückwunsch dazu.

Sind die Argumente eigentlich bewusst nicht für sinnvolles OO zutreffend, sondern nur für Objekte als Datencontainer, die man bei Prozeduraler Programmierung üblicherweise nutzt?
*Dabei* musst du dich durch die Daten hangeln - mit OO dagegen kannst du es anders lösen (und machst das bei vernünftigem OO auch).




knotenpunkt hat gesagt.:


> Wenn ich jetzt aus den Anemic-Objekten richtige Objekte mache, sprich funktionalität dazuimplementiere, dann arbeitet die funktionalität auf THIS, also auf den Daten des Objekts selbst. Und das macht das ganze unflexibel, da ich ja nur auf den THIS Daten arbeiten darf/kann.
> Also werden unabhängige Serviceklassen/prozeduren eingeführt um in die ganze Bude wieder etwas Schwung/dynamic zu bringen^^


Und eine Prozedur kann nur auf den ihr übergebenen Daten arbeiten, ist Prozedual jetzt etwa noch stärker eingeschränkt?

Das Objekte mit sich selbst arbeiten, habe ich bisher weder als Einschränkung noch als Unflexibel  empfunden...
Ganz im Gegenteil, eine Einschränkung ist doch völlig nötig. Wie soll denn ein Entwurf, bei dem alles Zugriff auf alles hat, in irgendwer Art und Weise überschaubar bleiben?



knotenpunkt hat gesagt.:


> Das Hauptthema ist die Frage, warum verwenden soviele Programmierer, wenn Sie meinen OO zu programmieren, ServiceKlassen.
> Meiner Meinung nach, weil Sie das reine OO nicht akzeptieren und das somit ein klares Indiz, dass es gescheitert ist.



Deine Meinung, von der dich auch niemand abbringen können wird.

Meine Meinung: Prozedural ist gescheitert, weil die meisten Leute OO oder Funktional programmieren.


----------



## mrBrown (18. Mai 2018)

Nur mal so als Beispielproblemstellung:

Es soll Konten geben, die einen Kontostand haben (Ganzzahlig reicht). Man kann den Kontostand erhöhen und verringern (um ganzzahlige Werte), er darf aber nie negativ sein.
Wie bildest du das Prozedural ab?


----------



## knotenpunkt (18. Mai 2018)

mrBrown hat gesagt.:


> Du kannst also rein prozedural ein "flexibel und generisch einsetzbares Programmgerüst" schreiben?


Ich denke du stimmst mir zu, wenn ich bspw. auf alle Daten von überall zugreifen kann, dass ich da sehr flexibel und dynamisch unterwegs bin. Klar, macht das den Code schwerer testbar, aber bei ordentlicher Strukturierung ist man auch hier sicher gut testbar und mit wenig Code unterwegs.



mrBrown hat gesagt.:


> Für mich fühlt es sich besser an, klaren und verständlichen Code zu schreiben, anstatt hochoptimierten...





mrBrown hat gesagt.:


> "ästhetisch aussehen" im Sinne von "klar, verständlich, strukturiert, etc" (was Lesbarkeit, Wartbarkeit und Testbarkeit impliziert) ist zumindest mir deutlich wichtiger als performant und Maschinennah...


Ich glaube das ist einfach eine subjektive Haltung dazu.
Aber, auch gut strukturierter Prozeduraler Code ist sehr gut lesbar, wartbar und testbar.
Warum nicht performance mit dazu nehmen, wenn man auf oo verzichtet?
Und ich glaube, vor allem weniger Code ist viel eher wartbar und erweiterbar als überdimensionierter oo-code?!



mrBrown hat gesagt.:


> Na gut, ich seh's ein: wenn man geschachtelte Objekte, die über Messages kommunizieren, als prozedural bezeichnet, programmieren alle prozedural.
> 
> Nur so als Frage: was ist für dich Objektorientiert, wenn es über Messages kommunizierende Objekte nicht sind?


Das ist ein Teil was OO ausmacht.
Ein weiterers Teil wäre Verhalten wäre: Verhalten und Daten zu einem Paket zusammengeschürt (und damit habe ich meine Probleme)




mrBrown hat gesagt.:


> In dem Fall, gibt es eben ein Objekte, was als Cache für das Zwischenergebnis fungiert, oder die Mail selbst kann das zurückgeben und cacht es entsprechend, alles kein Hexenwerk...
> 
> gibt zig Varianten, ohne die genauen Anforderungen zu kennen, kann man da keine von Anfang an richtige Lösung liefern - genausowenig bei der Prozeduralen Variante.
> 
> ...


So programmiere ich viel Code, also 5 Klassen um einen UseCase abzudecken. Das ganze ist dann zudem schlecht erweiterbar.
Nein ich habe für die gleiche Anwendung dann keine 17 Prozeduren.
Und möchte ich hier etwas erweitern, reichen schon 1-2 weitere Prozeduren aus.
Ich code somit zielorientiert und nicht overheadorintiert



mrBrown hat gesagt.:


> Und wo packst du die zum Versenden nötigen Daten jetzt hin, damit sie weniger Platz als in der OO-Variante brauchen? Oder übernimmt dann die DB das verschicken, und deine Anwendung benutzt die Daten gar nicht?


Die ein oder andere Datenbank kann EXEC aufrufe^^
in der prozeduralen Anwendung lade ich mir EXAKT die Daten, die ich brauche.
BSP, ein zielgerichtete SELECT anweisung mit diversen JOINS
OO und relational passen nicht zusammen.
In der OO müsste ich ganze Tabellen laden, diese zu Graphen zusammenbauen. Meinetwegen via lazy-loading Daten nachladen etc. pp und anschließend traversieren.



mrBrown hat gesagt.:


> Du forderst: "vernünftiges und vor allem flexibles und dynamisch einsetzbares domain-model"
> 
> Definier doch mal bitte, was deiner Meinung nach ein eben dieses ist?
> 
> Ein domain-model ist für eine spezifische Problemdomäne da - was muss da für dich flexibles und dynamisch sein?


ich definiere mir meine Datenstrukturen. Wenn ich eine Datenbank verwende also die Datenentitäten mit entsprechenden Schlüsseln.

So und jetzt je nach UseCase, den ich brauche, picke ich mir entsprechende zusammenaggregierte Daten aus der Datenbank heraus und arbeite damit. Dies kann von einer Prozedur/Service-Klasse oder auch mehreren erledigt werden. Verwende ich mehrere Prozeduren, baue ich das ganze somit Modular auf.

ein BSP:

ein User kauft sich auf meiner Webseite irgendwas:
Die Hauptprozedur fragt deligierend dann erstmal bei meiner Warenwirtschaftsprozedur nach ob Artikel verfügbar.
Wenn ja dann ruft diese die Rechnungsprozedur, Versandprozedur, Loggingproezdur, Warenwirtschaftsprozedur2 auf und erledigt damit den UseCase. Diese Proezduren haben unter Umständen selbst weitere Unterprozeduren.
Die Daten aus der Datenbank, anderweitigen API-Quellen holen sich diese Proezeduren selbstständig.
Im Falle dessen dass ich jetzt nur eine Datenbankanbindung habe und nicht auf externe APIs setze kann ich somit auch noch ganz toll das ganze transactional umsetzen..... also falls irgendwo was schief gehen sollte.

Somit arbeite ich zwar bis zu einem gewissen Grad global auf den Daten, aber durch die modulare Trennung von Rechnungsprozeduren, Warenwirtschaf............. schränke ich den globalen Spielraum wieder etwas ein.
Somit bin ich hochflexibel und auch nicht an irgendwelche Objektgraphen gebunden.




mrBrown hat gesagt.:


> Ein Service-Layer, welches die gesamte Business-Logik enthält, hat nichts mit OO zu tun - und eben das kritisiert Fowler!
> Ein Service, ohne "-Layer", nach DDD, ist aber eben nicht zu ersetzen und gehört durchaus zur Problemdomäne. Leseempfehlung (von Fowler): Domain Driven Design.
> 
> Aus "ein kleiner Teil des Objekt-Orientierten Designs ist prozedural" ist für mich auch noch kein "besser ganz auf OO verzichten"...


Warum lässt sich dann eine Anwendung nicht 100%ig oo bauen?
In welchen Fällen verwendest du selbst Services, in welchen Fällen nicht?
Wie entscheidest du das von Anfang an. Vor allem wenn du dein System gut erweiterbar aufbauen möchtest.




mrBrown hat gesagt.:


> Gute Erkenntnis: schlecht umgesetztes OO ist schlecht. Herzlichen Glückwunsch dazu.
> 
> Sind die Argumente eigentlich bewusst nicht für sinnvolles OO zutreffend, sondern nur für Objekte als Datencontainer, die man bei Prozeduraler Programmierung üblicherweise nutzt?
> *Dabei* musst du dich durch die Daten hangeln - mit OO dagegen kannst du es anders lösen (und machst das bei vernünftigem OO auch).


Könntest du hierzu mal ein Beispiel posten, wie du das bei vernünftigen OO lösen würdest?
Ganz allgemein würde mich interessieren, wie du schlechtes  umgesetztes OO von gutem OO abgrenzt






mrBrown hat gesagt.:


> Und eine Prozedur kann nur auf den ihr übergebenen Daten arbeiten, ist Prozedual jetzt etwa noch stärker eingeschränkt?
> 
> Das Objekte mit sich selbst arbeiten, habe ich bisher weder als Einschränkung noch als Unflexibel empfunden...
> Ganz im Gegenteil, eine Einschränkung ist doch völlig nötig. Wie soll denn ein Entwurf, bei dem alles Zugriff auf alles hat, in irgendwer Art und Weise überschaubar bleiben?



Ein OO-Konstrukt sollte meiner Meinung nach etwas langlebigeres sein. Eine Prozedur arbeitet ja nur kurz einmal mit ihren übergebenen Daten.
Methoden in diesem langlebigen Konstrukt, sind eingeschränkt, da sie nur mit der starren langlebigen Situation arbeiten sollten/dürfen. kurzlebige zusammenaggregierte Daten in einer Prozedur kann ich immer wieder frisch/neu zusammensetzen. Auch in Abhängigkeit des Algorithmuses. Also schön flexibel und dynamisch.
Also ein weiterer Punkt PRO Prozedur bzw. PRO Daten und Verhalten gehören nicht zusammen, nicht auf langlebige Sicht.

Zu zweiterem: Das setzt aber eine festverdrahtete in sich geschlossene Objektlandschaft vorraus.
Ein Entwurf, der nicht auf alle Daten zugriff hat, wird unflexibel. Wie greifst du bspw. vom MotorradObjekt auf das Sonnenobjekt zu und zwar exakt auf die Sonneninnentemperatur, sodass dein MotorradObjekt irgendwas machen kann, sollte dieser Anwendungsfall von Anfang an noch nicht vorgehsehen sein.
Um diesen Datenzugriff zu ermöglichen, musst du jetzt einiges erweitern.
Eventuell private Daten der Sonne freigeben, seis über ein getSonnenInnenTemperatur()...... Zwischenobjekte, also sprich Objekte die im Objektgraphen zwischen Motorrad und Sonne liegen, müssen diese Information irgendwie weitergeben, etc. pp
Das ist doch kein sinnvoller Entwurf mehr?!

Ausserdem stellt sich dann auch noch die Frage, sollte für die MotorradMotrensteuerung nicht nur die SonnenInnenTemperatur von Interesse sein, sondern allerlei anderes auch noch, gehört das fachlich dann überhaupt in eine Objektmethode des Motorrads/Motorradsmotors? Oder ist hier nicht sogar ein Service sinnvoller?




mrBrown hat gesagt.:


> Nur mal so als Beispielproblemstellung:
> 
> Es soll Konten geben, die einen Kontostand haben (Ganzzahlig reicht). Man kann den Kontostand erhöhen und verringern (um ganzzahlige Werte), er darf aber nie negativ sein.
> Wie bildest du das Prozedural ab?


Er darf nie negativ werden, wenn ein KontoInhaber diese Transaction macht.
Ein Admin darf das Konte des Users aber auch gerne mal ins Negative abrutschen lassen.
Das Verhalten gehört meiner Meinung nach nicht zum Konto, sondern zum Anwendungsfall
Ein klares Indiz dafür, dass Daten und Verhalten getrennt werden müssen.

Oder das Konto darf nicht negativ werden, wenn es 7 Uhr abends ist, der User eine negativen Schufaeintrag hat und wenn der Milchbauer vom Nebenort mindestens 70% seiner Photovoltaikanlage in den letzten 2Wochen als Eigenverbrauch verwendet hat.


Vllt. aber möchte ich diesen UseCase nicht von Anfang an haben, sondern wirklich erstmal Konto darf nicht negativ werden. Ich möchte aber trotzdem die Möglichkeit haben, es zu meinem erweiterten UseCase hingehend zu erweitern.
Wie würdest du das machen?
Auch unter dem Gesichtspunkt betrachtet, dass ein nerviges Entlanghageln des Objektgraphen nicht erwünscht ist. Wie komme ich zu den Informationen 7Uhr, 70%, Nachbar....... Ohne dass ich mich in einem komplexen Objektgraphen entlanghangeln muss?


*****************************************************************


Meniskusschaden hat gesagt.:


> Das ist eben der gängige Weg, objektorientiertes Design umzusetzen, wenn man nur eine prozedurale Sprache hat. Ist wohl eher ein Argument pro OO.


Nein: OO != Polymorphie
OO == Verhalten und Daten zusammengekapselt
OO == Austausch via Messages
und noch ein paar Kriterien

Zum Thema polymorphie ist mir gerade noch ein weiteres OO Designproblem aufgefallen.
Man nehme bspw. ein Dreieck (Klasse Dreieck)
In der Schule wird einem gelehrt, dass bspw das Dreick am besten selbst weiß wie es sich zeichnen soll


Die Polymorphie besteht in dem Fall darin, dass sich bei aufruf der draw()-Methode das geometrische Unterobjekt Dreieck anders selbst zeichnen wird, wie die draw()-Methode eines Vierecks.

Problem: Wo soll sich das Dreieck hinzeichnen?: Auf ein Canvaselement bspw!
Ist das aber wirklich die Aufgabe des Dreiecks, sich auf das Canvasobjekt zu zeichnen?
Meiner Meinung nach gehört diese Funktionaltät nicht in die Dreiecksklasse.
Sie gehört meiner Meinung nach in ein Modul, das für Zeichnen zuständig ist.

Möchte ich das Dreieck wiederverwenden, in einem System, in dem rein gar nichts gezeichnet wird, ist ein Dreieck ohne derartiges Verhalten definitiv besser aufgehoben.
Und das macht die Proezudurale programmierung auch so schön wiederverwendbar.
Ich schmeisse entsprechende Prozeduren raus, wenn ich sie woanders nicht brauche, oder ich nehme welche dazu und erweitere das system so.



@mrBrown

Was mir immer noch nicht ganz klar ist:

ich habe eine KlassenGraphStruktur, die wie folgt aussehen könnte.


```
class X
{

K übergerordnetes Objekt; //also sprich hier ist eine Referenz drinnnen von dem Objekt, das X enthält

T memVariable1 -> Y memVariable2 aus T -> memVariable3 aus Y
usw

methode1();
methode2();
methode3();

}
```
//ja klasse und klasseninstanz etwas vermischt, aber ich denke es wird klar, was ich meine

1 Frage ) wie greife ich von methode1 auf irgendwas von memVariable3 zu?
Eventuell: ich hangle mich im Objektgraphen entlang (aber du meintest, das wäre nicht sinnvoll)

2 Frage )
das ganze ist doch dann auch wieder global zu sehen, weil sich methode1 sich die Daten selbst holt
Ich habe lediglich den Overhead des Graphenentlanghangelns drinnen.

3 Frage )
greift methode2 auf K zu, bzw. ganz allgemein die Existenz von K in X macht meinen Objektgraphen zyklisch
Ist das sinnvoll in OO?

4 Frage )
Nehmen wir an X ist ein Konto:
Es soll in dem Konto ein Betrag/Variable geändert werden.
Es wird dazu memVariable3 aus Y benötigt, ABER auch in dem Objektgraphen nicht vorhanden, ein anderes Konto X...... das ich aber zur Compilezeit noch nicht kenne, sondern erst dynamisch ermitteln muss.
Ganz generell, dieser Objektgraph wie oben angegeben ist ein ein starres Gebilde........ und mindestens aber Teil einer längerlebigen Struktur.

Für viele UseCases brauche ich nur kurzlebige strukturen...... und da finde ich es quatsch einen Objektgraphen aufzubauen, DO_METHODE() ausführen...... Objektgraphen dem Destruktur/GC zuzuführen.

Meine Idee wäre hier: Ich brauche mal wieder eine Prozedur, die das übergeordnet erledigt.
Also habe ich wieder eine Service-Klasse, die aber kein reines OO darstellt.
Wie würdest du das in reines OO umwandeln?

5 Frage )
Viele Use-Cases wollen keine starre Strukur, also kein vorgegebenen Objektgraphen, sondern entscheiden erst zur Laufzeit, welche Daten sie genau benötigen.
Wie würdest du das OO umsetzen?



Noch eine ganz allgemeine Frage:
Wenn du deine Software iterativ aufbaust, am Anfang noch nicht genau weißt wie du was du haben möchtest, wie programmierst du da, bzw. wie gehst du da vor, wie ist dein Buildprozess.
Das Problem sieht man ja am Konto mit dem negativen Kontostand. Wenn ich ein USeCase habe, den aber erst im laufe meines programmierens erarbeite, wie gehst du da vor?
Aufwändige Refactorings sollten ausgeschlossen sein, da diese Vorgehensweise (der iterative,  top-bottom.... Aufbau) zur Programmiermethodik gehören soll.
Ich möchte eine Software so aufbauen, dass ich sie immer gut und schmerzfrei erweitern kann, das sehe ich irgendwie bei der OO nicht gegeben, bei PP dagegen schon.


lg knotenpunkt


----------



## mrBrown (18. Mai 2018)

knotenpunkt hat gesagt.:


> Ich denke du stimmst mir zu, wenn ich bspw. auf alle Daten von überall zugreifen kann, dass ich da sehr flexibel und dynamisch unterwegs bin. Klar, macht das den Code schwerer testbar, aber bei ordentlicher Strukturierung ist man auch hier sicher gut testbar und mit wenig Code unterwegs.


Nein, wenn von überall alles verändert werden kann, hast du einen großen Haufen Scheiße produziert.

Daran ist überhaupt nichts wartbar, strukturiert oder testbar.



knotenpunkt hat gesagt.:


> Ich glaube das ist einfach eine subjektive Haltung dazu.
> Aber, auch gut strukturierter Prozeduraler Code ist sehr gut lesbar, wartbar und testbar.
> Warum nicht performance mit dazu nehmen, wenn man auf oo verzichtet?
> Und ich glaube, vor allem weniger Code ist viel eher wartbar und erweiterbar als überdimensionierter oo-code?!


gut strukturierter Code ist lesbar, wartbar und testbar.
Gut strukturierten Code (mit klaren Zuständigkeiten, Abhängigkeiten etc) erreicht man häufig am besten mit OO.

Weniger Code produziert man mit Prozeduralem Code nicht zwingend - oft sogar ganz im Gegenteil.




knotenpunkt hat gesagt.:


> So programmiere ich viel Code, also 5 Klassen um einen UseCase abzudecken. Das ganze ist dann zudem schlecht erweiterbar.
> Nein ich habe für die gleiche Anwendung dann keine 17 Prozeduren.
> Und möchte ich hier etwas erweitern, reichen schon 1-2 weitere Prozeduren aus.
> Ich code somit zielorientiert und nicht overheadorintiert



Ich habe 5 Klassen, wenn es 5 *verschiedene* Zuständigkeiten gibt. Daran ist dann nichts schlecht erweiterbar.

Um aber mal deine Argumentation zu benutzen:

Ich schreibe als 5 Prozeduren, um die 5 Aspekte eines UseCases abzudecken. Das ganze ist dann schlecht erweiterbar.
Möchte ich in der OO-Variante etwas erweitern, reicht schon eine entsprechende Klasse.
Ich code somit zielorientiert und nicht overheadorintiert



knotenpunkt hat gesagt.:


> ich definiere mir meine Datenstrukturen. Wenn ich eine Datenbank verwende also die Datenentitäten mit entsprechenden Schlüsseln.
> 
> So und jetzt je nach UseCase, den ich brauche, picke ich mir entsprechende zusammenaggregierte Daten aus der Datenbank heraus und arbeite damit. Dies kann von einer Prozedur/Service-Klasse oder auch mehreren erledigt werden. Verwende ich mehrere Prozeduren, baue ich das ganze somit Modular auf.


Und wo ist jetzt der relevante Unterschied, der das ganze bei OO weniger flexibel macht?

Ich definiere meine Klassen, die sich *aus* den Use-Cases ergeben. Mit diesen arbeite ich dann.

Kommen *andere* Use-Cases dazu, muss man in beiden Fällen was anpassen.



knotenpunkt hat gesagt.:


> Warum lässt sich dann eine Anwendung nicht 100%ig oo bauen?
> In welchen Fällen verwendest du selbst Services, in welchen Fällen nicht?
> Wie entscheidest du das von Anfang an. Vor allem wenn du dein System gut erweiterbar aufbauen möchtest.


Ich verwende Services in den Fällen, in denen es sinnvoll ist.
Ich entschiede das, indem ich nicht einfach wild drauf los programmiere, sondern erstmal vernünftig modelliere.

Einen vernünftigen Entwurf brauchst du *immer*, das löst sich nicht durch die Wahl des Programmier-paradigmas.



knotenpunkt hat gesagt.:


> Könntest du hierzu mal ein Beispiel posten, wie du das bei vernünftigen OO lösen würdest?
> Ganz allgemein würde mich interessieren, wie du schlechtes umgesetztes OO von gutem OO abgrenzt


Ähm, wie man"durchhangeln" durch Objektgraphen vermeidet? Information-Hiding!
Die nutzende Klasse gehen die Interna der genutzen nichts an.
Aber wir vermeidest du denn prozedural das durchhangeln durch Datenstrukturen, zb um ein bestimmtes Kind eines Baumes zu finden?

Zu "gutes OO": du redest doch die ganze Zeit von Fowler, lies doch einfach mal irgendwas von ihm? Eine zusätzliche Leseempfehlung habe ich hier auch schon mehrfach geliefert, die können das wesentlich besser erklären als ich...



knotenpunkt hat gesagt.:


> Ein OO-Konstrukt sollte meiner Meinung nach etwas langlebigeres sein. Eine Prozedur arbeitet ja nur kurz einmal mit ihren übergebenen Daten.


*Deiner* Meinung nach. Meiner nicht.



knotenpunkt hat gesagt.:


> Methoden in diesem langlebigen Konstrukt, sind eingeschränkt, da sie nur mit der starren langlebigen Situation arbeiten sollten/dürfen. kurzlebige zusammenaggregierte Daten in einer Prozedur kann ich immer wieder frisch/neu zusammensetzen. Auch in Abhängigkeit des Algorithmuses. Also schön flexibel und dynamisch.
> Also ein weiterer Punkt PRO Prozedur bzw. PRO Daten und Verhalten gehören nicht zusammen, nicht auf langlebige Sicht.


Gehören *deiner Sicht* nach nicht zusammen.



knotenpunkt hat gesagt.:


> Zu zweiterem: Das setzt aber eine festverdrahtete in sich geschlossene Objektlandschaft vorraus.


Nö, setzt es nicht.
Spätes Binden = nicht festverdrahtet ist einer der wesentlichen Punkte von OO.



knotenpunkt hat gesagt.:


> Ein Entwurf, der nicht auf alle Daten zugriff hat, wird unflexibel. Wie greifst du bspw. vom MotorradObjekt auf das Sonnenobjekt zu und zwar exakt auf die Sonneninnentemperatur, sodass dein MotorradObjekt irgendwas machen kann, sollte dieser Anwendungsfall von Anfang an noch nicht vorgehsehen sein.
> Um diesen Datenzugriff zu ermöglichen, musst du jetzt einiges erweitern.
> Eventuell private Daten der Sonne freigeben, seis über ein getSonnenInnenTemperatur()...... Zwischenobjekte, also sprich Objekte die im Objektgraphen zwischen Motorrad und Sonne liegen, müssen diese Information irgendwie weitergeben, etc. pp
> Das ist doch kein sinnvoller Entwurf mehr?!
> ...



Konstruierter, als ein Motoradobjekt auf die Innentemperatur der Sonne zugreifen zu lassen, ist nicht möglich gewesen?

*Wenn* das Motorrad Zugriff auf die Umgehung braucht, dann hat es Zugriff auf die Umgebung, in der es sich befindet.
*Wenn* die Sonneninnentemperatur ermittelbar ist, gibt es entsprechende Methoden/Objekte/Messages.
*Wenn* die Anforderungen vorher keinen Zusammenhang von Sonne und Motorrad vorgesehen haben, muss ich anpassen.
*Wenn* mein Entwurf schlecht ist, muss ich viel anpassen.
Wenn er halbwegs gut ist, übergebe ich nur dem Motorrad die Umwelt (mit der Sonne) und stelle die Sonneninnentemperatur in der Sonne zur Verfügung, zwei Änderungen + was auch immer das Motorrad mit der Sonneninnentemperatur machen soll.

*Wenn* für die MotorradMotrensteuerung die SonnenInnenTemperatur relevant ist, gehört das natürlich zur MotorradMotrensteuerung. Warum sollte denn ein künstliches Konstrukt eingeführt werden, welches die Motorensteuerung und die SonnenInnenTemperatur kennt und weiß, wie beide zusammenwirken?


Aber das ganze mal prozedural betrachtet: Irgendwo gibt es ein Motorrad-Struct und ein Sonnen-Struct.
Das MotorradMotrensteuerung wird irgendwo in einer lieg geschachtelten Prozedur verändert. Wie bekommst du da jetzt ohne Änderung das Sonnenobjekt hin? Global ein einzelnes Sonnenstruct vorhalten, welches dann jeder verändern kann (zb einfach die SonnenInnenTemperatur negieren)?


Ich hätte übrigens beim ersten *Wenn* noch mal gewaltig über die Anforderungen nachgedacht.




knotenpunkt hat gesagt.:


> Er darf nie negativ werden, wenn ein KontoInhaber diese Transaction macht.
> Ein Admin darf das Konte des Users aber auch gerne mal ins Negative abrutschen lassen.
> Das Verhalten gehört meiner Meinung nach nicht zum Konto, sondern zum Anwendungsfall
> Ein klares Indiz dafür, dass Daten und Verhalten getrennt werden müssen.
> ...


Nö, ein klares Indiz, dass du die Anforderungen so umbiegst, dass sie dir besser passen.
Die Anforderungen war klar: *Der Kontostand darf durch Abheben nicht negativ werden*.



knotenpunkt hat gesagt.:


> Vllt. aber möchte ich diesen UseCase nicht von Anfang an haben, sondern wirklich erstmal Konto darf nicht negativ werden. Ich möchte aber trotzdem die Möglichkeit haben, es zu meinem erweiterten UseCase hingehend zu erweitern.
> Wie würdest du das machen?
> Auch unter dem Gesichtspunkt betrachtet, dass ein nerviges Entlanghageln des Objektgraphen nicht erwünscht ist. Wie komme ich zu den Informationen 7Uhr, 70%, Nachbar....... Ohne dass ich mich in einem komplexen Objektgraphen entlanghangeln muss?


Wie würdest du es denn machen?
Wie kommt die entsprechenden Prozedur an die Uhrzeit, die Photovoltaikanlage und den Nachbarn? (ohne, dass du dich durch irgendwelche Structs hangeln musst)



knotenpunkt hat gesagt.:


> Nein: OO != Polymorphie
> OO == Verhalten und Daten zusammengekapselt
> OO == Austausch via Messages
> und noch ein paar Kriterien


Durch messages hast du quasi Polymorphie, da verschiedene Objekte verschieden auf die gleiche Message reagieren können.



knotenpunkt hat gesagt.:


> Zum Thema polymorphie ist mir gerade noch ein weiteres OO Designproblem aufgefallen.
> Man nehme bspw. ein Dreieck (Klasse Dreieck)
> In der Schule wird einem gelehrt, dass bspw das Dreick am besten selbst weiß wie es sich zeichnen soll
> 
> ...



*Wenn* es ein grafisches Dreiecks-Element ist, ist es ganz offensichtlich Aufgabe des Dreiecks, sich selbst zu zeichnen. Das ist nämlich dann genau die Funktionalität, für die dieses Dreieck da ist.

*Wenn* es ein Dreieck ohne Bezug zur Ausgabe ist, ist es nicht Aufgabe des Dreiecks, sich zu zeichnen.
Ersteres Dreieck kann aber intern alles an letztes Dreieck delegieren, sodass man keine doppelte Funktionalität hat.


Das schöne an OO-Programmierung: das System ist flexibel und dynamisch. Brauche ich ein Viereck, erstell ich einfach eine Viereck-Klasse, und muss *nichts anderes* anpassen.

ganze anders bei Prozeduraler-Programmierung: brauche ich Vierecke, muss ich *jede* Prozedur, die mit Formen arbeitet, ändern. An zig Stellen müssen dann die Eigenheiten eines Vierecks bekannt sein, das ganze ist also völlig verstreut im gesamten Programm, anstatt an einer Stelle gebündelt zu sein.


"Und das macht die OO-Programmierung auch so schön wiederverwendbar.
Ich schmeisse entsprechende Objekte/Klassen raus, wenn ich sie nicht brauche, oder ich nehme welche dazu und erweitere das System so."
Da die Abhängigkeiten der Objekte klar definiert sind, hält ich durch rausnehmen auch der Schaden in Grenzen.
Wenn aber Alles auf alles zugreifen kann, kann ich nichts gefahrlos entfernen, ohne irgendwas kaputt zu machen




knotenpunkt hat gesagt.:


> ich habe eine KlassenGraphStruktur, die wie folgt aussehen könnte.


Ich habe ein Struct, was so aussieht:

```
struct X
{

K übergerordnetes struct; //also sprich hier ist eine Referenz drinnnen von dem struct, das X enthält

T variable1 -> Y variable2 aus T -> variable3 aus Y
}
```

und drei Methoden:
`methode1();methode2();methode3();`
Beantworte bitte einmal selbst deine drei Fragen.



knotenpunkt hat gesagt.:


> 1 Frage ) wie greife ich von methode1 auf irgendwas von memVariable3 zu?
> Eventuell: ich hangle mich im Objektgraphen entlang (aber du meintest, das wäre nicht sinnvoll)


Frage: warum braucht methode1 Dinge von Objekten, die es gar nicht kennt?
Im Zweifel: es bittet T um die entsprechenden Daten. Das memVariable3 in irgendeinem Unterobjekt existiert, weiß X im Optimalfall nicht



knotenpunkt hat gesagt.:


> 2 Frage )
> das ganze ist doch dann auch wieder global zu sehen, weil sich methode1 sich die Daten selbst holt
> Ich habe lediglich den Overhead des Graphenentlanghangelns drinnen.


Keine Ahnung was du damit meinst, global ist da ganz sicher nichts.
T *ist Teil von* X, Y *ist Teil von* T. nicht Y und T sind global.
(analog: Stuhl steht im Zimmer, Zimmer ist in nem Haus, was ist daran bitte global?)



knotenpunkt hat gesagt.:


> 3 Frage )
> greift methode2 auf K zu, bzw. ganz allgemein die Existenz von K in X macht meinen Objektgraphen zyklisch
> Ist das sinnvoll in OO?


nicht ohne Grund vermeidet man Zyklen, soweit möglich.
Sind Zyklen in Structs sinnvoll, bei Prozeduraler Programmierung?



knotenpunkt hat gesagt.:


> 4 Frage )
> Nehmen wir an X ist ein Konto:
> Es soll in dem Konto ein Betrag/Variable geändert werden.
> Es wird dazu memVariable3 aus Y benötigt, ABER auch in dem Objektgraphen nicht vorhanden, ein anderes Konto X...... das ich aber zur Compilezeit noch nicht kenne, sondern erst dynamisch ermitteln muss.
> ...


Ja, für sowas kann man Services nutzen. Services sind aber durchaus mehr, als nur reine Prozeduren.

Die Service-Klasse kann aber in diesem Fall auch keine Service-Klasse, sondern einfach ein "Bank-Objekt" sein, welches die Transaktion vornimmt.



knotenpunkt hat gesagt.:


> Ganz generell, dieser Objektgraph wie oben angegeben ist ein ein starres Gebilde........ und mindestens aber Teil einer längerlebigen Struktur.
> 
> Für viele UseCases brauche ich nur kurzlebige strukturen...... und da finde ich es quatsch einen Objektgraphen aufzubauen, DO_METHODE() ausführen...... Objektgraphen dem Destruktur/GC zuzuführen.



Weder sind Objektgraph starre Gebilde, noch müssen sie langlebig sein.

Prozeduren (bzw Aufruf-Graphen) sind starre Gebilde, nicht Objekte!



knotenpunkt hat gesagt.:


> 5 Frage )
> Viele Use-Cases wollen keine starre Strukur, also kein vorgegebenen Objektgraphen, sondern entscheiden erst zur Laufzeit, welche Daten sie genau benötigen.
> Wie würdest du das OO umsetzen?


OO hat keine feste Struktur, das späte Binden zur Laufzeit ist eines der wichtigsten Merkmale!


Abgesehen davon: wie entscheiden denn zur Compiler-Zeit statisch gebundene Prozeduren magisch zur Laufzeit irgendwas?




knotenpunkt hat gesagt.:


> Noch eine ganz allgemeine Frage:
> Wenn du deine Software iterativ aufbaust, am Anfang noch nicht genau weißt wie du was du haben möchtest, wie programmierst du da, bzw. wie gehst du da vor, wie ist dein Buildprozess.
> Das Problem sieht man ja am Konto mit dem negativen Kontostand. Wenn ich ein USeCase habe, den aber erst im laufe meines programmierens erarbeite, wie gehst du da vor?
> Aufwändige Refactorings sollten ausgeschlossen sein, da diese Vorgehensweise (der iterative, top-bottom.... Aufbau) zur Programmiermethodik gehören soll.
> Ich möchte eine Software so aufbauen, dass ich sie immer gut und schmerzfrei erweitern kann, das sehe ich irgendwie bei der OO nicht gegeben, bei PP dagegen schon.


Die Probleme hast du *genauso* bei PP.
Das du sie dort nicht und nur bei OO siehst, liegt an deinem Mangelnden Verständnis von OO (und deinem extremen Hype von PP).

Ansonsten:
Noch eine ganz allgemeine Frage:
Wenn du deine Software iterativ aufbaust, am Anfang noch nicht genau weißt wie du was du haben möchtest, wie programmierst du da, bzw. wie gehst du da vor, wie ist dein Buildprozess.
Das Problem sieht man ja am Konto mit dem negativen Kontostand. Wenn ich ein USeCase habe, den aber erst im laufe meines programmierens erarbeite, wie gehst du da vor?
Aufwändige Refactorings sollten ausgeschlossen sein, da diese Vorgehensweise (der iterative, top-bottom.... Aufbau) zur Programmiermethodik gehören soll.
Ich möchte eine Software so aufbauen, dass ich sie immer gut und schmerzfrei erweitern kann, das sehe ich irgendwie bei der PP nicht gegeben, bei OO dagegen schon.


----------



## Meniskusschaden (18. Mai 2018)

knotenpunkt hat gesagt.:


> Ich denke du stimmst mir zu, wenn ich bspw. auf alle Daten von überall zugreifen kann, dass ich da sehr flexibel und dynamisch unterwegs bin. Klar, macht das den Code schwerer testbar, aber bei ordentlicher Strukturierung ist man auch hier sicher gut testbar und mit wenig Code unterwegs.


Verstehe ich das richtig, dass du da gerade für die extensive Verwendung von globalen Variablen wirbst? Dann müssen wir kaum über OO diskutieren, denn das wäre auch innerhalb der prozeduralen Programmierung schon weitab vom Mainstream.
Selbst wenn du diese tolle Strukturierung schaffen würdest, würde dir das wenig nützen, weil dir jedes andere Teammitglied über unkontrollierte Seiteneffekte alles zerschiessen könnte. Diese Art von "Flexibilität" will man durch Einführung des Geheimnisprinzips ja gerade vermeiden.


knotenpunkt hat gesagt.:


> Warum lässt sich dann eine Anwendung nicht 100%ig oo bauen?


Wer hatte denn jemals die Absicht das zu 100% zu tun? Wenn man eine adäquate Klassenhierarchie geschaffen hat, wird innerhalb der Methoden natürlich vieles prozedural gemacht.


knotenpunkt hat gesagt.:


> Nein: OO != Polymorphie


Polymorphie ist nicht dasselbe wie OO, aber ein wichtiger Bestandteil davon. Ein Motor ist auch kein Auto, aber trotzdem ein wichtiger Bestandteil davon.


knotenpunkt hat gesagt.:


> OO == Verhalten und Daten zusammengekapselt


Ja. Setzt man in OO-Sprachen mit Objektattributen und -methoden um und in prozeduralen Sprachen mit Verbundtypen und Funktionszeigern. Das sind zwei unterschiedliche technische Möglichkeiten, OO-Design zu implementieren.


knotenpunkt hat gesagt.:


> Die Polymorphie besteht in dem Fall darin, dass sich bei aufruf der draw()-Methode das geometrische Unterobjekt Dreieck anders selbst zeichnen wird, wie die draw()-Methode eines Vierecks.
> 
> Problem: Wo soll sich das Dreieck hinzeichnen?: Auf ein Canvaselement bspw!
> Ist das aber wirklich die Aufgabe des Dreiecks, sich auf das Canvasobjekt zu zeichnen?
> ...


Natürlich benötigt man keine Zeichenmethode, wenn man nicht zeichnen will. Wenn man aber ein Shape-Objekt haben möchte, das ein Dreieck zeichnet, kann es sich die Mathematik doch von einem Triangle-Objekt erledigen lassen. Dazu muß man auch keine Prozeduren raus werfen oder rein kopieren, sondert verwendet einfach seine Triangle-Klasse wieder.


----------



## AndiE (18. Mai 2018)

So richtig kann ich der Argumentation nicht folgen. Ich habe doch als erstes eine Use-Story. Nehmen wir mal als Beispiel eine Lieferscheinerstellung. In einem Lager gibt es Waren, die an Kunden verschickt werden und dabei werden Lieferscheine erstellt. Ich würde ich als erstes den "best case" modellieren, aber schnell darauf kommen, dass ich erst dem "worst case" benötige. Im "worst case" kennt das System weder einen Kunden noch eine Ware, und natürlich keinen Lieferschein. Im "best case" sind Kunde und Ware im System enthalten. In Falle des "worst case"muss ich also erst die Ware erstellen und dann den Kunden, und dann beides in einem Lieferschein verbinden. Wahrscheinlich würde ich die Waren und die Kunden noch als Collections erstellen. 
Diese "use cases" "Ware erstellen" und "Kunde erstellen", erstellen ein neues Objekt, dass sie einfach den vorhandenen Collections hinzufügen. 
Im Normalfall würde ich in der OOP die attribute private deklarieren und die getter und setter als public. Offensichtich wurde die Methode Ware.entimm(int anzahl) auch public sein. Da ich eine Formularansicht habe, habe ich auch immer ein aktuelles Objekt der Klasse Ware, das ich bearbeite. Und der Lieferschein wächst bei Ausführung dynamisch.
Will ich nun eine Anzahl Fuhrunternehmer mit verwalten, die die Lieferungen zum Kunden bringen, dann habe ich zwischen der Klasse Fuhrunternehmen und der Klasse Lieferscheine ein m:n-Kardinalität. In der Regel würde ich sogar eine Super-Klasse Geschäftspartner erstellen, von der Kunde und Fuhrunternehmer "erben", weil diese Klasse die anderen beiden generalisiert.

Natürlich könnte ich das auch prozedural machen, aber "addnewItem()" liest sich schwerer und ist unverständlicher als "ItemList.addItem()". Bei zweitem weiß ich, wer was macht, und durch die längere  Schreibweise haben wir beim ersten auch mehr Fehlerwahrscheinlichkeit.


----------



## mrBrown (6. Jun 2018)

@knotenpunkt, ist die Diskussion schon vorbei?


----------



## knotenpunkt (6. Jun 2018)

@mrBrown Nein, hatte nur in letzter Zeit kaum Zeit^^, aber ich bereite schon den nächsten Diskussionschritt/Beitrag in diesem Thread hier vor^^


----------



## knotenpunkt (20. Jun 2018)

Hey,



mrBrown hat gesagt.:


> Weniger Code produziert man mit Prozeduralem Code nicht zwingend - oft sogar ganz im Gegenteil.


Da wäre ich aber an einem Beispiel interessiert^^



mrBrown hat gesagt.:


> Möchte ich in der OO-Variante etwas erweitern, reicht schon eine entsprechende Klasse.


Wie genau definierst du erweitern?
erweitern heisst für mich, teilweise bestehende Funktionlität weiter verwenden und diese um einen Gesichtspunkt zu erweitern. Also eine weitere Prozedur, die bestehende Prozeduren in irgendeiner Weise verwendet.




mrBrown hat gesagt.:


> Kommen *andere* Use-Cases dazu, muss man in beiden Fällen was anpassen.


Es kommt glaube ich darauf an, wie man erweitert. 
Es gibt meiner Meinung nach zwei Erweiterungsklassen (ich verwende hier den Begriff Klasse nicht im Zusammenhang von Programmierung, sondern einfach als normalen Sprachgebrauch^^)

Erweitere ich horizontal oder vertikal?
Sprich erweitere ich Funktionalität aussen rum (heisst ich verwende subsysteme einfach so wie sie sind -> So ein Art Schichtensystem) oder erweitere ich switch-cases, in der oo dann weitere Typen, polymorphe Aufrufe (switch-case und polymorphe Typen, sind ja das gleiche^^)

Bei zweiterem hast du recht, da muss ich bei beiden was anpassen.
Bei ersterem, die Frage an dich, wie erweiterst du sinnvoll in der oo "Funktionalität aussen rum".
//Ich habe dazu noch keine Meinung, würde mich auf ein Beispiel von dir freuen^^


Zu dem Switch-Case habe ich aber gleich mal ne Frage:
{
data x;
data y;
data z;

switch(variable k)
case 1;
case 2;
usw
}

im case 1 werden x und y verändert im case 2 werden y und z verändert/zugegriffen/oder whatever.
variable k steht erst zur Laufzeit und erst bei aufruf dieses Blocks { } fest! 
wie würdest du das sinnvoll ins oo umformen?

ich würde sagen es ist schwierig solange k keinen fest defnierten/unflexiblen Zustand aufspannt. 
Außerdem ist es kritisch für oo, da sowohl case 1 als auch case 2 y benötigen, entsprechende cases aber nicht jeweils x und z benötigen.



mrBrown hat gesagt.:


> Konstruierter, als ein Motoradobjekt auf die Innentemperatur der Sonne zugreifen zu lassen, ist nicht möglich gewesen?
> 
> *Wenn* das Motorrad Zugriff auf die Umgehung braucht, dann hat es Zugriff auf die Umgebung, in der es sich befindet.
> *Wenn* die Sonneninnentemperatur ermittelbar ist, gibt es entsprechende Methoden/Objekte/Messages.
> ...



So konstruiert finde ich das Beispiel nicht. Es zeigt, dass ich in speziellen Fällen, eben solche Anforderungen brauche und dies in der pp kein Problem darstellt.

Punkt 1 (Motorrad und Umgebung):
Das Motorrad hat die Umgebung und die Umgebung hat das Motorrad -> zirkuläre Abhängigkeit (du hast ja selbst geschrieben dass zirkuläre Abhängigkeiten schlecht sind)

Punkt 2 (Sonneninnentemperatur und entsprechende Methoden/Objekte/Messages)
Ich hatte ja ähnliches beispiel:
 struct X 
{
T mV1 -> mV2 -> mv3 ->.....
}

Du meintest hier, das im best case X mV2 und mV3...... nicht kennen sollte

Auf die Sonneninnentemperatur bezogen, würde das folgendes bedeuten:
Das Motorrad kennt nur die Umgebung, also nicht die Sonne
Oder noch überspitzter, Der Motorradmotor kennt nur sein umliegendes Motorrad und nichtmal die Umgebung.

Wie kommt also das Motorrad zur Sonneninnentemperatur.
Wenn du die Umgebung jetzt zu einer Art Facade umfunktionierst, dann hast du da zig-Tausend Methoden drinnen stehen. Motorrad fragt Umgebung ->giveMeSonneninnenTemperatur 
und die Sonne delegiert das weiter z.B an die WeltallFacade
Das würde bedeuten, ich müsste in der Umgebung alle Methoden mit aufnehmen, die die memberVariable der Umgebung auch besitzen (und von aussen, hier jetzt das Motorrad benötigt werden) usw.
Das ist doch ein Krampf!

Also wie würdest du das richtig designen?


Punkt 3 (schlechter Entwurf):
Was ist ein guter und was ist ein schlechter Entwurf. Vllt hättest du da ein paar Antworten für mich auch auf konkreter Ebene und nicht nur abstrakt^^

Punkt 4 (Sonnen-Struct)
Warum nicht global, zumindest Teilglobal.
Sollte es in einem anderen Modul (Modul !=oo) liegen, kann man sich ja überlegen, das ganze nur über eine Wächterprozedur accessable zu machen. 
Was mir hier aber wichtig ist, ich füge hier nicht daten und behaviour zusammen, sondern ich habe nur Behaviour.
Die Daten können meintwegen in der Datenbank liegen, sie können via fremd-API zugreifbar sein.
Und vor allem, die Daten haben keine Abhängigkeiten untereinander. 
Um zu deinem Bankkonto zurückzukommen: Irgendwie hat dein Bankkonto sagen wir mal zwei mem_variablen, die was auch immer aussagen, was genau ist egal^^

möchte ich gewährleisten, dass mem_variable1 und 2 aus dem Bankkonto nur eine bestimmte Zustandsmenge annehmen dürfen, dann baue ich dafür eine Wächtermethode, die eben nur Elemente aus meiner eingeschränkten Zustandsmenge zulässt, oder diese sogar selbst baut! (angereichterte Wächtersetterfunktionen oder angereichterte Buisnessfunktionen). Das coole an der prozeduralen Programmierung ist aber jetzt im Vergleich zur OOP, dass diese Daten hier nicht in einer location gekapselt werden müssen. Zudem kann es sein, dass diese zwei mem_variablen auch nur in der einen Prozedur zueinander in Relation stehen.



mrBrown hat gesagt.:


> Nö, ein klares Indiz, dass du die Anforderungen so umbiegst, dass sie dir besser passen.
> Die Anforderungen war klar: *Der Kontostand darf durch Abheben nicht negativ werden*.


Ich mache die Anforderungen komplexer. 
Mich würde interessieren, wie du das mit meiner Anforderung machen würdest.
Wie ich es mit deiner machen würde, steht direkt über diesem Zitat..... Eine Wächterprozedur, die deinen Use-Case abdeckt.



mrBrown hat gesagt.:


> Wie würdest du es denn machen?
> Wie kommt die entsprechenden Prozedur an die Uhrzeit, die Photovoltaikanlage und den Nachbarn? (ohne, dass du dich durch irgendwelche Structs hangeln musst)


Falls entsprechende Daten im Speicher stehen sollten, habe ich mir vorher optmierte direktZugriffCachingstrukturen gebaut. Falls nicht:
In der OOP bin ich mehr oder weniger gezwungen einen Graphen aufzubauen und damit zu arbeiten. 
in der PP kann ich optimierte Datenstrukturen her nehmen. Dazu zählt auch das Wissen über Alignment im Speicher und anderes (diverse Hashtabeln, Binärvektoren, etc pp). Wenn ich möchte kann ich natürlich auch eine Baum/Graphstruktur aufbauen und damit arbeiten. Ich bin in der PP diesbezüglich sehr flexibel.
Sollten die Daten in der Datenbank liegen, kann mich mir die Effizienz des Datenbanksystems zu nutze machen^^

Sowie ich dich und auch die OOP im Allgemeinen verstanden habe, ist das aber streng genommen keine OOP wenn ich mir die Daten zusammenglaube und dann an einer Stelle einen Algorithmus ausführe. OOP besteht ja aus verteilten Algorithmen. 
Meiner Meinung nach kann man mit verteilten Algorithmen einen "gesammelten" Algorithmus (bspw. eine Prozedur)
in seiner Gesamtheit nur abbilden, wenn ich State und Steuerungsvariablen mitdurchschleife etc pp. Und wenn dann noch transaktionen/atomarität etc pp dazukommen....... gute nacht^^

Der Testbarkeit zuliebe finde ich bei verteilte Algorithmen jetzt auch nicht wirklich so gut gegeben.




mrBrown hat gesagt.:


> *Wenn* es ein grafisches Dreiecks-Element ist, ist es ganz offensichtlich Aufgabe des Dreiecks, sich selbst zu zeichnen. Das ist nämlich dann genau die Funktionalität, für die dieses Dreieck da ist.
> 
> *Wenn* es ein Dreieck ohne Bezug zur Ausgabe ist, ist es nicht Aufgabe des Dreiecks, sich zu zeichnen.
> Ersteres Dreieck kann aber intern alles an letztes Dreieck delegieren, sodass man keine doppelte Funktionalität hat.
> ...



Wie genau sieht für dich Delegieren aus?
DreiecktGraphisch-> ruft methode getXCoordinate() auf in DreieckNormal und dieses -> ruft getXCoordinate() auf sich selbst auf. Das ist für mich eben overheadorientiertes programmieren^^




mrBrown hat gesagt.:


> Frage: warum braucht methode1 Dinge von Objekten, die es gar nicht kennt?
> Im Zweifel: es bittet T um die entsprechenden Daten. Das memVariable3 in irgendeinem Unterobjekt existiert, weiß X im Optimalfall nicht


Wie soll es dann an die Daten kommen?
Ok ich kann facadenhaft die Schnittstellen platt klopfen, sprich ich biete in T Methoden an, die nichts anderes tun, als einfaches Weiterdeligieren an Methoden von memVariable3
Das ist doch nicht sinnvoll.




mrBrown hat gesagt.:


> Keine Ahnung was du damit meinst, global ist da ganz sicher nichts.
> T *ist Teil von* X, Y *ist Teil von* T. nicht Y und T sind global.
> (analog: Stuhl steht im Zimmer, Zimmer ist in nem Haus, was ist daran bitte global?)


Naja ich finde schon, ob ich jetzt via eines direkten Access an die Daten komme oder via Hangelns, ist für das Ergebnis egal. Ich habe in der Konsquenz dann die Daten.
Nur Zweiteres bedeutet viel Overhead in der Umsetzung



mrBrown hat gesagt.:


> nicht ohne Grund vermeidet man Zyklen, soweit möglich.
> Sind Zyklen in Structs sinnvoll, bei Prozeduraler Programmierung?


Zyklen in prozeduraler Programmierung? Wie meinst du das?
Wie du vorhin ja selbst geschrieben hast: Die Motorsteuerung muss Zugriff auf sein Embeddendes Objekt, also die Umgebung haben, somit würde ich zirkulär programmieren. 
Also wie würdest du die Motorsteuerung auf die Innentemperatur der Sonne zugreifen lassen?




mrBrown hat gesagt.:


> Ja, für sowas kann man Services nutzen. Services sind aber durchaus mehr, als nur reine Prozeduren.
> 
> Die Service-Klasse kann aber in diesem Fall auch keine Service-Klasse, sondern einfach ein "Bank-Objekt" sein, welches die Transaktion vornimmt.



Und dann brauche ich später Transfers zwischen Banken usw.
Jetzt könnte ich ja gemäß Bottom-Up hier wieder ein "SammelObjekt"-Schreiben. vllt. eine Bankenvereinigungsklasse^^
Möchte ich aber jetzt nur einen Transfer innerhalb einer Bank machen, dann muss ich die Schnittstellen aus der Bankklasse wieder facadenhaft nach aussen reichen, also in der Bankenvereinigungsklasse Delegationsmethoden anbieten. Oder die Bankenvereinigungsklasse muss wieder Internas rausgeben, sprich eine Methode getBank() haben. Diese Lösung findest du selbst nicht so gut, wie du bei meinem Beispiel mit X->mem1->mem2->mem3 geschrieben hast.



mrBrown hat gesagt.:


> Weder sind Objektgraph starre Gebilde, noch müssen sie langlebig sein.
> 
> Prozeduren (bzw Aufruf-Graphen) sind starre Gebilde, nicht Objekte!


Die Struktur der Prozeduren ist starr, ja das ist richtig^^
Die Ausführung dagegen ist hochdynamisch und zwar wesentlich dynamischer als bei Objekten^^
Und das möchte ich jetzt etwas näher erklären:
Prozeduren:
Jeder verschiedenartige Input hat ein anderes Verhalten zur Folge (auch durch switch-cases gegeben)
das macht das meinetwegen auch etwas schwerer testbar, aber somit auch hoch dynamisch^^

Objekte:
Jedes andere Objekt mit anderem State verhält sich eigentlich genauso wie ich es eben unter dem Punkt Prozedur geschrieben habe.
Möchte ich in einem Batch-Prozess dieses Verhalten hervorrufen, muss ich sowas in der Art machen:
new ActionObjekt(data1,data2,data3)->process(); //anschließend kann der GC das ActionObjekt wegwerfen.
Empfinde ich nicht so sinnvoll, hier den Heap und den GC zu stressen, obwohl man auch direkt callFunction(data1,data2,data3) aufrufen könnte.

Also habe ich in der Objektwelt eher starre  Gebilde
Irgendwo mal vereinzelt ein C=new Objekt(dataA,dataB,dataC); und dann rufe ich auf C methoden auf.
Dieses verhalten ist gemäß der konstruktordaten dataA bis dataC, sehr eingeschränkt.
Flexibilität sehe ich hier nicht!




mrBrown hat gesagt.:


> OO hat keine feste Struktur, das späte Binden zur Laufzeit ist eines der wichtigsten Merkmale!
> 
> 
> Abgesehen davon: wie entscheiden denn zur Compiler-Zeit statisch gebundene Prozeduren magisch zur Laufzeit irgendwas?


prozeduren, durch switch-cases und zwar je nach aktuell stattfindender parameterübergabe.

OO kann das gleiche Verhalten vorweisen, aber wie ich schon direkt über diesem zitat geschrieben habe:
ActionObjekte sind nicht so sinnvoll.
So zeigen zwar auch Objekte in dem Punkt dynamisches Verhalten auf. Diese Dynamik ist aber nicht flexibel, da die Objekte mit der Dynamik zwar konfiguriert werden (Konstruktoraufruf new Object(dataA,dataB,dataC)), diese Flexibilität dann aber nicht weiter zur Laufzeit haben. (sonst wären wir ja wieder bei den ActionObjects^^)
Ich denke du kannst nachvollziehen, was ich meine, oder?



mrBrown hat gesagt.:


> Ansonsten:
> Noch eine ganz allgemeine Frage:
> Wenn du deine Software iterativ aufbaust, am Anfang noch nicht genau weißt wie du was du haben möchtest, wie programmierst du da, bzw. wie gehst du da vor, wie ist dein Buildprozess.
> Das Problem sieht man ja am Konto mit dem negativen Kontostand. Wenn ich ein USeCase habe, den aber erst im laufe meines programmierens erarbeite, wie gehst du da vor?
> ...



Touche^^, aber meinen Text empfinde ich als richtiger^^





Meniskusschaden hat gesagt.:


> Wer hatte denn jemals die Absicht das zu 100% zu tun? Wenn man eine adäquate Klassenhierarchie geschaffen hat, wird innerhalb der Methoden natürlich vieles prozedural gemacht.


Und wo ist dann der Unterschied zu gut strukturiertem prozeduralen Programmieren?



Meniskusschaden hat gesagt.:


> Polymorphie ist nicht dasselbe wie OO, aber ein wichtiger Bestandteil davon. Ein Motor ist auch kein Auto, aber trotzdem ein wichtiger Bestandteil davon.


Ich wollte damit nur klarstellen, dass OO nicht Polymorphie ist.
Polymorphie kann in OO verwendet werden, genauso aber auch in prozeduraler Programmierung





AndiE hat gesagt.:


> Natürlich könnte ich das auch prozedural machen, aber "addnewItem()" liest sich schwerer und ist unverständlicher als "ItemList.addItem()". Bei zweitem weiß ich, wer was macht, und durch die längere Schreibweise haben wir beim ersten auch mehr Fehlerwahrscheinlichkeit.


Zweiteres setzt vorraus, dass ich die ItemList vor mir habe.
Bei ersterem muss ich die ItemListe nicht vor mir haben. 
Wenn ich als Identifikator bspw. eine ID, ein SuchString etc pp übergebe, dann liegt es in der Verantwortung der addNewItem() Prozedur die Daten zu holen, und nicht mir bei mir als Client, diese Daten bereitzustellen bzw. vorzuenthalten. Und das ist schon sehr wertvoll^^




AndiE hat gesagt.:


> Offensichtich wurde die Methode Ware.entimm(int anzahl) auch public sein.


Hier sehe ich allgemein das Problem, dass man viel overhead programmiert. Und zwar: Einen Wrapper um bestehende Collection-Klassen.


So jetzt hätte ich mal noch ein paar Praxisbeispiele, wo ich versucht habe einen OO-Ansatz umzusetzen, aber nicht wirklich glücklich darüber bin. Im folgenden werde ich ausführen, warum ich darüber nicht glücklich bin, bzw. welche Probleme ich da so sehe^^


Problem 1:

Wenn ich jetzt bei den Collection-Klassen bleibe:
Ich habe oft folgendes Problem:
wenn ich Daten abspeichere, dann speichere ich die unterschiedlich indexiert ab.
Sprich einmal sequenziell in einer ArrayList
Ein zweitesmal in einer HashMap mit dem Key Name
Ein drittesmal in einer Hasmap mit dem Key Alter


class User
{
string name;
string alter;
string mail;
string gender;
//weitere....
}

class IrgendEinUserContainer
{
ArrayList<User> sequenziell;
HashMap<String,User>indexedByName;
HashMap<String,User>indexedByAlter;
}


So kann ich später je nachdem mit welchem Suchindex ich drauf zugreifen möchte, entsprechend schnell an das UserObjekt gelangen.
Ist das sinnvoll das so zu machen?
Weil bei jedem push/remove muss ich alle indexStrukturen anpassen.

Wie ich SQL an der Stelle liebe. Einfach ein entsprechender Suchstring eingeben und ich bekomme super schnell mein Ergebnis (das habe ich geschrieben, weil ich früher viel web-zeugs gemacht habe^^)

Möchte ich in der OO-Welt einen weiteren Index hinzufügen, muss ich einiges anpassen. Bei SQL dagegen interessiert mich das nicht!



Problem 2:
verteilte Algorithmen:

@mrBrown du hast vorhin ja geschrieben, wenn X überhaupt Informationen von memVariable3 braucht.
Wenn nicht, dann impliziert das, dass in memVarbiable3 selbst entsprechender Algorithmus definiert ist.
Aber das geht ja leider nicht überall, dass man Algorithmen aufteilt.
Und genau deshalb brauche ich managed/service-Prozeduren, wo der Algorithmus an einer zentralen Stelle definiert ist und sich die Daten holt/via Argumente bekommt und basierend auf diesen dann entsprechendes Programmverhalten zeigt^^

Ich habe bspw ne RestApi von einer Gartenbeleuchtung 

Was für Module habe ich:
Kommunikationsmodul (tcp/connection.... Restparsing etc pp)
SmartHomeModul
BelechtungsschalterHighLevel
RelaisSchalterLowLevel


Wo bearbeite ich den Request?
Der Request kommt im Kommunikationsmodul an..... theorethissch könnte ich ihn hier schon komplett abarbeiten
dazu würde ich mir entsprechende State-Daten aus untergeordneten Modulen/Objekte holen

Ich kann den Request aber auch irgendwie weitergeben

Aber dann hat mein Kommunikationsmodul nur noch zur Aufgabe Requests weiterzudeligieren und im Falle eines "Protokollfehlers" rauszufiltern und wegzuschmeissen.


Ok funktioniert alles -> ich delegiere weiter an das SmartHomeModul
Warum würde ich als prozedural-denkender Mensch spätestens hier die die komplette Logik verbauen?

Das mag ich erklären:

Das RelaisSchalterModul hat dafür Sorge zu tragen, dass das Relai-Modul immer nur alle 2sec einen Umschaltvorgang tätigen darf, sollte es  sich bei einem Mehrkanalsrelais um den gleichen Relaikanal handeln.

Das BeleuchtungsschalterHighLevel Modul sorgt dafür, dass ein entsprechender User immer nur alle 30sec etwas schalten darf.

Ausserdem sollte in der Requestantwort detailiert stehen, im Falle eines Negativs, warum der Schaltvorgang nicht funktioniert hat.

Zudem, sollte das Relaismodul in der letzten Stunde bereits 30 Schaltvorgänge getätigt haben und ein User X selbst in der letzten Stunde 20 Schaltvorgänge gemacht haben, dann wird das ganze System für 3h gesperrt

Was ich damit sagen möchte, das ist alles so sehr verwoben, dass es nicht viel Sinn macht zu versuchen den Algorithmus da aufzuteilen.


Vllt möchte ich auch noch folgendes miteinbauen:
Wenn User X 50RestCalls gesendet hat und nur 10 Schaltvorgänge getätigt hat, das Relaismodul 5 Schaltvorgänge verzeichnet hat und das alles in den letzten 40min, auch dann sollte eine Sperre, diesmal für 5h eingerichtet werden.

Sprich ich brauch in dem Use-Case bzw. in dem Algorithmus, Daten aus allen Modulen/Ebenen (vorwärt/rückwärts/zirkulierend, etc pp^^)

Eine Prozedur, die die Daten erhält, sie erhalten kann oder whatever ist hier wesentlich besser geeignet als der Versuch den Algorithmus aufzuteilen, was ja auch gar nicht geht.


Problem 3

Vllt. geht das ganze ja doch?!

Also was ich auch schon öfters gemacht habe:
Bei vielen MethodenCalls schleife ich einen Art Kontext mit durch^^

Bei einer Mischpultsteuerung die ich mal programmiert habe, habe ich bspw. folgenden Kontext mitdurchgeschleift.
Mitdurchgeschleift bedeutet in dem Fall, dass in einer Event-basierten-Architektur, auch die die abgefeuerten Events, Delegationen, etc, pp den Kontext miterhalten haben.

Z.b.

channel5.setEQDBHighLevelBand(3,kontext);

kontext enhält folgende Daten
{
isNetwork
isUserCall
isAutomaticCall
isDCACall
}

Warum brauche ich die Daten?
Im Falle des DCA-Calls unterbinde ich somit Schleifen, sollte es sich um einen Fader handeln, der selbst in einer DCA-Gruppe ist.
IsNetwork bedeutet, ich habe die Parameteränderung von einem ClientRechner aus dem Netwerk erhalten/oder vica versa...... Das isNetwork unterbindet dann später im NetworkEventProcessor, dass der Request wieder zurückgeleitet wird, was dann übers netzwerk eine endlosRekursion zur Folge hätte

....

Also wie man sieht, kann man Algorithmen schon etwas aufteilen, ABER ich muss Steuerungskontext Daten mitdurchschleifen?!
Eine andere Lösung sehe ich da nicht?!
Oder seht ihr da eine andere Lösung?


Also nochmal zusammenfassend was stört mich an OO:
-der Versuch einen zentralen Algorithmus in einen dezentralen umzuwandeln, was oft nicht funktioniert
-ich brauche das Objekt an der Stelle, wo ich etwas mit Ihm bzw. dessen Daten anstellen möchte //siehe addItem Beispiel
-unnötige Abhängigkeiten -> sobald ich membervariablen in einem Objekt zusammenfasse und auf diesem Methoden definiere, so ist die Methode immer abhängig von ALLEN Membervariablen, auch wenn nicht alle benötigt werden.
-sehr unflexibel -> siehe Beispiel  mit ActionObjekt/NormalenObjekt/SwitchCases
-weiteres


soweit mal wieder


lg knotenpunkt


----------



## AndiE (20. Jun 2018)

Zu 1.:
Hier kommt es doch auch auf die Modellierung an. Angenommen, ich hätte eine Bibliotheksverwaltung, und das Buch-Objekt hat die Membervariablen (Platz,Titel, Autor, Kategorie, Umfang). Dann kann ich ja nach den ersten 3 Variablen indizieren. Dann habe ich doch zumindest 2 Listen, die aufsteigend Titel und Autor beinhalten. 
Die OOP entspricht für mich dem natürlichen Denken. 

Erzeuge ein Buchobjekt. Nimm das Bibliotheksobjekt. Füge de Bibliotheksobjekt das Buchobjekt hinzu.

Und  damit fertig. Was da im Hintergrund passiert, ist mir egal. Das macht doch das Programmieren viel übersichtlicher und damit auch wartbarer.

Ich brauche eine inizierung? Wer besitzt die? Sicher das Bibliotheksobjekt. Das hole ich mir und kann dann damit arbeiten.


----------



## mrBrown (20. Jun 2018)

knotenpunkt hat gesagt.:


> Da wäre ich aber an einem Beispiel interessiert^^


Gefühlt alles, wo Polymorphie benutzt wird...




knotenpunkt hat gesagt.:


> Wie genau definierst du erweitern?
> erweitern heisst für mich, teilweise bestehende Funktionlität weiter verwenden und diese um einen Gesichtspunkt zu erweitern. Also eine weitere Prozedur, die bestehende Prozeduren in irgendeiner Weise verwendet.


Ich definiere das kaum anders - dem Programm neue Funktionalität hinzufügen.
In welcher Form ist egal, relevant ist nur, dass das Programm am Ende mehr Funktionalität hat.



knotenpunkt hat gesagt.:


> Es kommt glaube ich darauf an, wie man erweitert.
> Es gibt meiner Meinung nach zwei Erweiterungsklassen (ich verwende hier den Begriff Klasse nicht im Zusammenhang von Programmierung, sondern einfach als normalen Sprachgebrauch^^)
> 
> Erweitere ich horizontal oder vertikal?
> ...


Okay, um meine ursprüngliche Aussage anzupassen: man muss die für den neuen Use-Case relevanten Teile anpassen 

Das "Funktionalität aussen rum" ohne Probleme klappt, ist doch einer der wesentlichen Punkte von OO. Bestehenden Teilen ist es vollkommen egal, wie sie genutzt werden - solange die der Spezifikation entsprechend genutzt werden, und das erzwingt man z.T. durch Kapselung.



knotenpunkt hat gesagt.:


> (switch-case und polymorphe Typen, sind ja das gleiche^^)


Ja, genau wie ein if+goto das gleiche ist wie while und for...also theoretisch schon, praktisch wird es aber ganz sicher nicht so genutzt^^




knotenpunkt hat gesagt.:


> Zu dem Switch-Case habe ich aber gleich mal ne Frage:
> {
> data x;
> data y;
> ...



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.




knotenpunkt hat gesagt.:


> So konstruiert finde ich das Beispiel nicht. Es zeigt, dass ich in speziellen Fällen, eben solche Anforderungen brauche und dies in der pp kein Problem darstellt.


Ein Motorrad, welches die Innentemperatur der Sonne kennt, zeigt vor allem, dass man, um sein Argument zu unterstützen, die absurdesten Dinge konstruiert 



knotenpunkt hat gesagt.:


> Das Motorrad hat die Umgebung und die Umgebung hat das Motorrad -> zirkuläre Abhängigkeit (du hast ja selbst geschrieben dass zirkuläre Abhängigkeiten schlecht sind)


Deshalb vermeidet man sie soweit möglich - ein Beispiel, in dem man sie zwingend braucht, kann man natürlich immer Konstruieren 



knotenpunkt hat gesagt.:


> Punkt 2 (Sonneninnentemperatur und entsprechende Methoden/Objekte/Messages)
> Ich hatte ja ähnliches beispiel:
> struct X
> {
> ...


Wenn(!) so etwas völlig absurdes nötig ist, könnte man über die Umgebung an die Sonne kommen und über das Motorrad an dessen Umgebung. Aber dann würde es bei mir daran scheitern, das man die Innentemperatur der Sonne nicht einfach weiß 

Aber mal andersrum gefragt: Wie würdest du so etwas sauber(!) designen?



knotenpunkt hat gesagt.:


> Punkt 3 (schlechter Entwurf):
> Was ist ein guter und was ist ein schlechter Entwurf. Vllt hättest du da ein paar Antworten für mich auch auf konkreter Ebene und nicht nur abstrakt^^


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.



knotenpunkt hat gesagt.:


> Punkt 4 (Sonnen-Struct)
> Warum nicht global, zumindest Teilglobal.
> Sollte es in einem anderen Modul (Modul !=oo) liegen, kann man sich ja überlegen, das ganze nur über eine Wächterprozedur accessable zu machen.
> Was mir hier aber wichtig ist, ich füge hier nicht daten und behaviour zusammen, sondern ich habe nur Behaviour.
> ...



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?



knotenpunkt hat gesagt.:


> Ich mache die Anforderungen komplexer.
> Mich würde interessieren, wie du das mit meiner Anforderung machen würdest.
> Wie ich es mit deiner machen würde, steht direkt über diesem Zitat..... Eine Wächterprozedur, die deinen Use-Case abdeckt.


Du gehst abet nicht wirklich zu nem Kunde und sagst dem "ich habe deine Anforderungen komplexer gemacht, weil deine Geschäftsregeln waren irgendwie doof und ich wollte sie gern anders. Das dein Geschäft jetzt nicht mehr Funktioniert ist mir egal. Benutz aber bitte meine Wächterprozedur".

Was ich mit deiner kontextlosen Wächterprozedur mache, hab ich ja auch schon gesagt: sie ignorieren. Warum sollte ich auch eine wild im Programm stehenden Prozedur nutzen, wenn die Daten eh global verfügbar sind und ich sie viel einfacher direkt benutzen kann?




knotenpunkt hat gesagt.:


> Falls entsprechende Daten im Speicher stehen sollten, habe ich mir vorher optmierte direktZugriffCachingstrukturen gebaut. Falls nicht:
> In der OOP bin ich mehr oder weniger gezwungen einen Graphen aufzubauen und damit zu arbeiten.
> in der PP kann ich optimierte Datenstrukturen her nehmen. Dazu zählt auch das Wissen über Alignment im Speicher und anderes (diverse Hashtabeln, Binärvektoren, etc pp). Wenn ich möchte kann ich natürlich auch eine Baum/Graphstruktur aufbauen und damit arbeiten. Ich bin in der PP diesbezüglich sehr flexibel.
> Sollten die Daten in der Datenbank liegen, kann mich mir die Effizienz des Datenbanksystems zu nutze machen^^


und das jetzt bitte in der prozeduralen Sprache Pascal.



knotenpunkt hat gesagt.:


> [...] OOP besteht ja aus verteilten Algorithmen. [...]


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




knotenpunkt hat gesagt.:


> Wie genau sieht für dich Delegieren aus?
> DreiecktGraphisch-> ruft methode getXCoordinate() auf in DreieckNormal und dieses -> ruft getXCoordinate() auf sich selbst auf. Das ist für mich eben overheadorientiertes programmieren^^


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.



knotenpunkt hat gesagt.:


> Wie soll es dann an die Daten kommen?
> Ok ich kann facadenhaft die Schnittstellen platt klopfen, sprich ich biete in T Methoden an, die nichts anderes tun, als einfaches Weiterdeligieren an Methoden von memVariable3
> Das ist doch nicht sinnvoll.


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.



knotenpunkt hat gesagt.:


> Zyklen in prozeduraler Programmierung? Wie meinst du das?
> Wie du vorhin ja selbst geschrieben hast: Die Motorsteuerung muss Zugriff auf sein Embeddendes Objekt, also die Umgebung haben, somit würde ich zirkulär programmieren.
> Also wie würdest du die Motorsteuerung auf die Innentemperatur der Sonne zugreifen lassen?



So meine ich Zyklen in Structs:

```
struct A {
  B b;
}
struct B {
  A a;
}
```

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.



knotenpunkt hat gesagt.:


> Und dann brauche ich später Transfers zwischen Banken usw.
> Jetzt könnte ich ja gemäß Bottom-Up hier wieder ein "SammelObjekt"-Schreiben. vllt. eine Bankenvereinigungsklasse^^
> Möchte ich aber jetzt nur einen Transfer innerhalb einer Bank machen, dann muss ich die Schnittstellen aus der Bankklasse wieder facadenhaft nach aussen reichen, also in der Bankenvereinigungsklasse Delegationsmethoden anbieten. Oder die Bankenvereinigungsklasse muss wieder Internas rausgeben, sprich eine Methode getBank() haben. Diese Lösung findest du selbst nicht so gut, wie du bei meinem Beispiel mit X->mem1->mem2->mem3 geschrieben hast.


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




knotenpunkt hat gesagt.:


> Prozeduren:
> Jeder verschiedenartige Input hat ein anderes Verhalten zur Folge (auch durch switch-cases gegeben)
> das macht das meinetwegen auch etwas schwerer testbar, aber somit auch hoch dynamisch^^


Also hast du Code, den fast jeder direkt als absolut unbenutzbar abtun würde?



knotenpunkt hat gesagt.:


> new ActionObjekt(data1,data2,data3)->process(); //anschließend kann der GC das ActionObjekt wegwerfen.
> Empfinde ich nicht so sinnvoll, hier den Heap und den GC zu stressen, obwohl man auch direkt callFunction(data1,data2,data3) aufrufen könnte.


In meiner lustigen, grad erfundenen Prozeduralen Sprache erzeugt jeder Prozeduraufruf 17GB an Daten auf dem Heap, welche mit 1Kb/sek erzeugt werden.
In realen OO-Sprachen kann das alles nur mit Allokation auf dem Stack oder sogar ohne jegliche Speicher-Allokation für Objekte passieren.

Also haben wir: Prozedural super langsam vs OO super schnell
(Vielleicht fällt dir jetzt auf, dass du aus "Konzept vs Konzept" ständig "schnelle Laufzeitumgebung vs langsame Laufzeitumgebung" machst - wenn du lieber darüber reden willst, solltest du einen dazu passenden Thread aufmachen.)


knotenpunkt hat gesagt.:


> Irgendwo mal vereinzelt ein C=new Objekt(dataA,dataB,dataC); und dann rufe ich auf C methoden auf.
> Dieses verhalten ist gemäß der konstruktordaten dataA bis dataC, sehr eingeschränkt.
> Flexibilität sehe ich hier nicht!


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



knotenpunkt hat gesagt.:


> ActionObjekte sind nicht so sinnvoll.
> So zeigen zwar auch Objekte in dem Punkt dynamisches Verhalten auf. Diese Dynamik ist aber nicht flexibel, da die Objekte mit der Dynamik zwar konfiguriert werden (Konstruktoraufruf new Object(dataA,dataB,dataC)), diese Flexibilität dann aber nicht weiter zur Laufzeit haben. (sonst wären wir ja wieder bei den ActionObjects^^)
> Ich denke du kannst nachvollziehen, was ich meine, oder?


Nö, kann ich nicht, weil es Unsinn ist. Siehe den Punkt hier drüber.




knotenpunkt hat gesagt.:


> Und wo ist dann der Unterschied zu gut strukturiertem prozeduralen Programmieren?



Was bedeutet für dich "gut strukturiert"?
Zusammengehörende Dinge zusammen legen ist es nicht, einzelne Teile nur bestimmte Dinge machen auch nicht (weil zu unflexibel).
Wenn ich alle deine Erklärungen zusammen nehme, hab ich völlig unstrukturierten prozeduralen Code vor Augen.



knotenpunkt hat gesagt.:


> Zweiteres setzt vorraus, dass ich die ItemList vor mir habe.
> Bei ersterem muss ich die ItemListe nicht vor mir haben.
> Wenn ich als Identifikator bspw. eine ID, ein SuchString etc pp übergebe, dann liegt es in der Verantwortung der addNewItem() Prozedur die Daten zu holen, und nicht mir bei mir als Client, diese Daten bereitzustellen bzw. vorzuenthalten. Und das ist schon sehr wertvoll^^



Das ist der Unterschied zwischen Dependeny Injection und dem großen Haufen Code, ersteres hat sich nicht ohne Grund durchgesetzt 



knotenpunkt hat gesagt.:


> Wie ich SQL an der Stelle liebe.


Glückwunsch, du hast erkannt, dass deklarative Sprachen oft toller sind als Prozedurale Sprachen  Gehe ich vollkommen konform mit 



knotenpunkt hat gesagt.:


> Ich kann den Request aber auch irgendwie weitergeben
> 
> Aber dann hat mein Kommunikationsmodul nur noch zur Aufgabe Requests weiterzudeligieren und im Falle eines "Protokollfehlers" rauszufiltern und wegzuschmeissen.


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?





knotenpunkt hat gesagt.:


> Was ich damit sagen möchte, das ist alles so sehr verwoben, dass es nicht viel Sinn macht zu versuchen den Algorithmus da aufzuteilen.


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



knotenpunkt hat gesagt.:


> Eine Prozedur, die die Daten erhält, sie erhalten kann oder whatever ist hier wesentlich besser geeignet als der Versuch den Algorithmus aufzuteilen, was ja auch gar nicht geht.


Wie würde denn die Prozedur aussehen? 2345 Zeilen und die tiefste Schachtelung etwa 19? 



knotenpunkt hat gesagt.:


> Also wie man sieht, kann man Algorithmen schon etwas aufteilen, ABER ich muss Steuerungskontext Daten mitdurchschleifen?!
> Eine andere Lösung sehe ich da nicht?!
> Oder seht ihr da eine andere Lösung?


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



knotenpunkt hat gesagt.:


> -der Versuch einen zentralen Algorithmus in einen dezentralen umzuwandeln, was oft nicht funktioniert


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



knotenpunkt hat gesagt.:


> -ich brauche das Objekt an der Stelle, wo ich etwas mit Ihm bzw. dessen Daten anstellen möchte //siehe addItem Beispiel


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



knotenpunkt hat gesagt.:


> -unnötige Abhängigkeiten -> sobald ich membervariablen in einem Objekt zusammenfasse und auf diesem Methoden definiere, so ist die Methode immer abhängig von ALLEN Membervariablen, auch wenn nicht alle benötigt werden.


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



knotenpunkt hat gesagt.:


> -sehr unflexibel -> siehe Beispiel mit ActionObjekt/NormalenObjekt/SwitchCases


Wie gesagt: der Punkt an sich ist schon völliger Unsinn.


----------



## AndiE (22. Jun 2018)

Einsprungspunkt in PP:

```
// Header
void functuin1();
void function2();

main(){
int auswahl;
switch(auswahl=menu()){
case 1: function1();
break;
case 2:function2();
break;
}
```

Einsprungspunkt in OOP

```
public class App{

static vord main(){
DatenObjekt do= new DatenObjekt();
AnsichtObjekt ao= new AnsichtObjekt(do);
ao.start();
```

Auf den ersten Blick scheint hier nur die switch-Anweisung in die AO-Klasse verrutscht. Für mich ist es aber unübersichtlich, die Header-Dateien vorher anzugeben. Noch blöder fand ich bei C, dass auch die structs in der Header-Datei liegen. Bei C++ hat man wenigstens die gesamte Klassendeklaration in der Header-Datei und nur die Methoden in der cpp.

Und hier unterscheidet sich OOP von PP ganz gewaltig. Auch sowohl die Konsolenanwendung als auch eine GUI wird im PP immer eine Zahl für die Auswahl zurückgeben. In der OOP ist das nicht so eindeutig. Der ActionListener wird bei einer GUI die entsprechende Methode aufrufen. Auf der Konsolenebene kann man das mit einem switch machen, aber auch anders. 

Und genau das ist der Vorteil. Ich muss nicht den ganzen Top-Down-Botton-Up-Zweig durchgehen und Dumpings setzen. Ich kann auch seperat Funktionalitäten( Klassen) schreiben und separat testen. Das könnte ich bei PP auch, aber ich kann Klassen durch einen Status beschreiben und den testen. Bei der PP werden Datenobjekte nie als solches gesehen und ich kann ihren Status auch nicht testen. Das ist von der Modellierung her ein gewaltiger Unterschied. 

Und aus diesem Ansatz heraus, das Objekte einen Status haben, erwächst ja auch die Grundlage, dass Nachrichten bei der OOP den Status der Objekte ändern. Dadurch kann ich letztendlich auch Multitasking und Threads(parallele Abarbeitung) machen, aber das nur so am Rande.


----------



## mrBrown (22. Jun 2018)

AndiE hat gesagt.:


> Für mich ist es aber unübersichtlich, die Header-Dateien vorher anzugeben. Noch blöder fand ich bei C, dass auch die structs in der Header-Datei liegen. Bei C++ hat man wenigstens die gesamte Klassendeklaration in der Header-Datei und nur die Methoden in der cpp.


Das sind Sprachdetails, die nichts mit dem Konzept zu tun haben...



AndiE hat gesagt.:


> Und hier unterscheidet sich OOP von PP ganz gewaltig. Auch sowohl die Konsolenanwendung als auch eine GUI wird im PP immer eine Zahl für die Auswahl zurückgeben. In der OOP ist das nicht so eindeutig. Der ActionListener wird bei einer GUI die entsprechende Methode aufrufen. Auf der Konsolenebene kann man das mit einem switch machen, aber auch anders.


Ich wüsste nicht, warum man in PP nicht Listenerbasiert arbeiten sollte? Man kann da ja auch durchaus Funktionen übergeben...



AndiE hat gesagt.:


> Dadurch kann ich letztendlich auch Multitasking und Threads(parallele Abarbeitung) machen, aber das nur so am Rande.


Das geht auch in PP 
Und sogar noch deutlich besser mit Funktionaler Programmierung, die völlig ohne veränderlichen Zustand auskommt...


----------



## AndiE (23. Jun 2018)

Nun müssen wir vielleicht auch mal sehen, was wir genau meinen. Nehme ich das "Prozedurale Programmierparadigma", dann sage ich, dass ich da den Programmablauf eindeutig in einem PAP oder NSD abbilden kann. Ich kann den Ablauf selbst bei strukturierter Programmierung mit einem Instruction-Pointer nachvollziehen. Nebenläufige Prozesse werden hardwaremäßig abgedeckt(DMA, CRT). Schon die Arbeit mit Prozessen widerspricht diesem Paradigma, wie ich es definiert habe. Selbst die Steuerung der Abarbeitung mit festgelegter Bearbeitungszeit( Drehscheibe), benötigt doch Objekte im Speicher, die Informationen zur Abarbeitung uns zum Status der Anwendungen haben. Also letztendlich Objekte im Sinne der OOP. Diese Abarbeitung, dass ich einen Prozess aufrufen der dann die anderen startet, finde ich typisch in OOP. Im Prinzip reiche ich alle Prozesse an die Hauptnachrichtenschleife weiter, die jedoch nicht das Programm wie bei der PP, sondern das Betriebssystem hält. Erfolgt eine zeitlang keine Nachricht, geht das System in "Idle"-Modus über und zeigt i.d.R. den Bildschirmschoner. 
Natürlich hat man das bei den "*-Commander" auch ohne OOP gemacht(glaube ich jedenfalls), aber die Übergabe von Funktionen ( void proc( function func1) ist meiner Ansicht nach nicht typisch PP.


----------



## mrBrown (23. Jun 2018)

AndiE hat gesagt.:


> Schon die Arbeit mit Prozessen widerspricht diesem Paradigma, wie ich es definiert habe.


Wie *du* es definiert hast. Für eine Diskussion darüber sollten wir aber lieber bei einer allgemein gültigen Definition bleiben.



AndiE hat gesagt.:


> Nehme ich das "Prozedurale Programmierparadigma", dann sage ich, dass ich da den Programmablauf eindeutig in einem PAP oder NSD abbilden kann.


Sowohl in PAP (zb join und fork in Flowcharts) als auch in NSD (Parallel-Processing Symbol) lassen sich parallele Prozesse abbilden.



AndiE hat gesagt.:


> Selbst die Steuerung der Abarbeitung mit festgelegter Bearbeitungszeit( Drehscheibe), benötigt doch Objekte im Speicher, die Informationen zur Abarbeitung uns zum Status der Anwendungen haben. Also letztendlich Objekte im Sinne der OOP. Diese Abarbeitung, dass ich einen Prozess aufrufen der dann die anderen startet, finde ich typisch in OOP.


Bitte lies dir noch mal die Definition von OOP im allerersten Beitrag durch.
Daten im Speicher sind noch lange keine Objekte im Sinne von OOP und haben mit OOP erstmal gar nichts zu tun. Der relevante Teil, Objekte bestehen aus Daten und Methoden und kommunizieren über Messages, ist bei "Daten im Speicher" keineswegs erfüllt.



AndiE hat gesagt.:


> Im Prinzip reiche ich alle Prozesse an die Hauptnachrichtenschleife weiter, die jedoch nicht das Programm wie bei der PP, sondern das Betriebssystem hält. Erfolgt eine zeitlang keine Nachricht, geht das System in "Idle"-Modus über und zeigt i.d.R. den Bildschirmschoner.


Keine Ahnung was du damit meinst, aber ein Bildschirmschoner hat sicherlich nichts mit PP vs OOP zu tun.



AndiE hat gesagt.:


> die Übergabe von Funktionen ( void proc( function func1) ist meiner Ansicht nach nicht typisch PP.


nur "nicht typisch" oder widerspricht es der Definition?


----------



## AndiE (23. Jun 2018)

Gut. das war jetzt zu doll. Aber um den Unterschied und den Vorteil zwischen OOP und PP mal zu demonstrieren, hilft der hier auch so strapazierte Taschenrechner. 

In der OOP würde ich eine Zahl als Objekt der Klasse "Zahl" definieren, die die Methoden "clean, addDigit, add, sub, div, mul und get" hat. Diese Methoden "Löschen, Fügen eine Stelle hinzu, Addieren, Subtrahieren, Dividieren, Multiplizieren und geben das Ergebnis aus." Offensichtlich kann ich diese Klasse "Zahl" einfach in die Klasse "Money" umwandeln, um Geldbeträge in Cent oder 1/10-Cent abzuspeichern. Daneben kann ich die Klasse natürlich auch für sich selbst testen, ohne eine GUI oder Menu-Stuktur zu haben.
Und bei einer Warenverwaltung bedeuten Item.add() und Bill.add() beides verschiedene Dinge: einmal das Hinzufügen einer Ware und einmal das Hinzufügen eines Rechnungspostens. Ich kann somit die Camel-Notation umgehen und die Methodennamen werden kürzer.
Das alles lässt doch OOP viel besser planen und leichter entwickeln. 
Natürlich kann ich den Taschenrechner mit Pp erstellen, aber es ist doch verständlicher wenn die Klasse "Rechner" zwei "Zahlobjekte" "res"(result) und "op"(operator) hält. Jeder Eingabe eines Zeichens ruft dann entweder eine Nachricht für das Objekt res oder op auf. Damit habe ich eben auch Darstellung und Berechnung voneinander getrenn und die Fehlersuche wird leichter. Statt "case '*': z= e1+e2;" rufe ich auf "case '*' : erg.mul(op);" . Ich finde letzteres besser.


----------



## mihe7 (23. Jun 2018)

mrBrown hat gesagt.:


> nur "nicht typisch" oder widerspricht es der Definition?


Der Punkt dürfte sein, dass man nicht dadurch prozedural programmiert, indem man Objekte auf structs und function pointer abbildet. Gleichzeitig sind function pointer wohl kein notwendiges Kriterium für PP. Insofern vereinfacht es die Sache schon, wenn man sie aus der Betrachtung rausnimmt.


----------



## mrBrown (24. Jun 2018)

AndiE hat gesagt.:


> Und bei einer Warenverwaltung bedeuten Item.add() und Bill.add() beides verschiedene Dinge: einmal das Hinzufügen einer Ware und einmal das Hinzufügen eines Rechnungspostens. Ich kann somit die Camel-Notation umgehen und die Methodennamen werden kürzer.


Na, das ist aber auch nur ein Pseudo-Beispiel...

Ob man jetzt `item.add()` oder `add(item)` schreibt, nimmt sich vom Schreibaufwand wirklich nichts (außer hier der gesparte Punkt in der PP Variante  ).
Abgesehen davon kann man durchaus eine PP-Sprache schreiben, in der das erste Argument auch in "Prefix-Notation" gegeben werden kann. Analog, zu Java mit Lombok und statischen Methoden.
Und genauso könnte man eine OO-Sprache schreiben, die zwar völlig Objektorientiert ist, in der aber der Message-Empfänger als erstes Argument übergebe werden muss 



AndiE hat gesagt.:


> Natürlich kann ich den Taschenrechner mit Pp erstellen, aber es ist doch verständlicher wenn die Klasse "Rechner" zwei "Zahlobjekte" "res"(result) und "op"(operator) hält. Jeder Eingabe eines Zeichens ruft dann entweder eine Nachricht für das Objekt res oder op auf. Damit habe ich eben auch Darstellung und Berechnung voneinander getrenn und die Fehlersuche wird leichter. Statt "case '*': z= e1*e2;" rufe ich auf "case '*' : erg.mul(op);" . Ich finde letzteres besser.



Grad so ein Rechner lässt sich ganz wunderbar mit Stack (reine Datenstrukturen sind ja wohl erlaubt? sonst halt n Array...) und Prozeduren abbilden, vor allem in polnischer Notation 

Ich bevorzuge zwar auch die OO-Variante - aber dann doch bitte nicht `case '*' : erg.mul(op);` (was auch nicht wirklich schöner ist als `case '*': z= e1+e2;`, eher hässlicher), sonder Objekt-Orientiert und gleich `operand.calc(first, second)` 




mihe7 hat gesagt.:


> Der Punkt dürfte sein, dass man nicht dadurch prozedural programmiert, indem man Objekte auf structs und function pointer abbildet. Gleichzeitig sind function pointer wohl kein notwendiges Kriterium für PP. Insofern vereinfacht es die Sache schon, wenn man sie aus der Betrachtung rausnimmt.


Das man nicht mehr wirklich p. p., wenn man beide miteinander verbindet, stimme ich voll zu, wurde ja auch schon weiter oben erwähnt 

Aber beide für sich genommen sind doch wesentlichen Teile von Prozeduraler Programmierung. Zumindest für eine Nachbildung von Listenern/Callbacks/HOF reicht auch die Übergabe von Prozeduren aus - aber keine Ahnung, ob man dass dann noch Prozedural nennt, wird aber zumindest häufig benutzt.


----------



## mihe7 (24. Jun 2018)

mrBrown hat gesagt.:


> wurde ja auch schon weiter oben erwähnt


Sorry, das habe ich wohl übersehen. 

Ich versuche mich, dem Thread zu nähern  Mir fehlt die Abgrenzung zwischen PP und OO. Es gibt in dem Thread zwar eine Definition von OO, nicht aber von PP (außer ich habe auch diese nicht gesehen). 

Der Argumentation von @knotenpunkt bzgl. der Flexibilität von PP kann ich nicht ganz folgen. Klar, es ist einfach in PP neue Prozeduren hinzuzufügen - so lange diese mit bereits existierenden Typen arbeiten. Umgekehrt ist es sehr viel aufwändiger, neue Typen hinzuzufügen. Außerdem steht der Abhängigkeitsgraph der betreffenden Prozeduren bereits zur Übersetzungszeit fest (außer man verwendet function pointer...) - was daran flexibel sein soll, ist mir nicht klar. Die Kanten zeigen dabei immer in Richtung low-level. Eine kleine Änderung einer Funktion auf niedriger Ebene und das Programm ist im A...


----------



## AndiE (24. Jun 2018)

@mrBrown: Der Taschenrechner war ein Beispiel, um OOP und PP miteinander zu vergleichen. Dabei gehe ich davon aus, dass die zugrundeliegende Maschine mit wahlfreiem Speicherzugriff arbeitet. Bei einer Stack- oder Queue-basierten Maschine sehe ich das Problem, dass der Stack typischerweise nur Daten eines Typs aufnehmen kann. Übrigens auch ein typisches Array. Man muss also hier auch Möglichkeiten schaffen, Daten auf dem Speicher abzulegen und wieder abzurufen. Wobei ich das hier nicht soweit auseinanderteilen möchte: Offensichtlich gibt es ja auch bei einem Programm mit wahlfreien Zugriff einen Adressstack, um die Unterprogramm-Aufrufe durchführen zu können und einen Datenstack, um Daten zwischen den Prozeduren übergeben zu können(der kann auch ein Queue sein). 

Eine der wichtigsten Dinge bei der OOP, selbst wenn ich mich an der Smalltalk-Syntax orientiere, ist doch, dass ein Aufruf typischerweise nicht nur einfach Präfix wie 
	
	
	
	





```
proc(arg)
```
, sondern doppelt Präfix 
	
	
	
	





```
obj.meth(member)
```
. erfolgt. Das bedeutet, dass ich dem Objekt obj eine Nachricht meth mit dem Argument member( oder mehreren) schicke. Auf den ersten Blick ist das bei der OOP zwar mehr Schreibarbeit, aber es bringt mir Sicherheit. Im übertragenen Sinne kann ich doch bei der PP sagen "Ich bin hier mitten im Wald und kaufe mir ein Brot". Bei der OOP dagegen habe ich "Bäcker, gib mir ein Brot". Und genau beim PP-Beispiel ist dann im täglichen Programmiergeschäft die Frage im Code: "Wo kommen diese Werte plötzlich her, die da benutzt werden?". Vergleichbare Sammelklassen mit final-Werten in OOP(Java) würden mit Global.PRICE_PER_DAY daherkommen. Dann weiß man als Programmierer aber auch, wo diese Konstante zu sehen ist, und zu ändern ist. 

Ich gehe übrigens nicht mit der Aussage des 1. Posts mit, dass Vererbung keine OOP ist. Ich habe zwar nicht gefunden, wie Klassen in Smalltalk definiert werden, würde aber sagen, es ist da auch möglich, die Funktionalität der Klasse mittels Nachricht zu erweitern, um so Member und Methoden einzufügen. Ich denke nämlich, dass das die konsequente Weiterführung dessen ist, was beim Übergang von der maschinennahen zur prozeduralen Programmierung erfolgt ist, nämlich die zunehmende Abstraktion. Wenn ich also Kontakte mittels Bitmuster schalte, dann würde ich das in der nächsten Stufe so abstrahieren, dass Kontakt_ein(int nummer) aufgerufen wird. Wie das erfolgt ist dann doch egal. Und diese PP-Darstellung würde ich doch in OOP so erweitern, dass ich erstmal eine Klasse "Kontakt" habe und diese erweitere zu solchen mit Selbsthaltung und verzögertem Ein- oder Ausschalten usw.


----------



## mihe7 (24. Jun 2018)

AndiE hat gesagt.:


> Ich gehe übrigens nicht mit der Aussage des 1. Posts mit, dass Vererbung keine OOP ist.


Vererbung ist kein notwendiges Kriterium für OO, genauso wenig wie Klassen.


----------



## mrBrown (24. Jun 2018)

AndiE hat gesagt.:


> @mrBrown: Der Taschenrechner war ein Beispiel, um OOP und PP miteinander zu vergleichen. Dabei gehe ich davon aus, dass die zugrundeliegende Maschine mit wahlfreiem Speicherzugriff arbeitet. Bei einer Stack- oder Queue-basierten Maschine sehe ich das Problem, dass der Stack typischerweise nur Daten eines Typs aufnehmen kann. Übrigens auch ein typisches Array. Man muss also hier auch Möglichkeiten schaffen, Daten auf dem Speicher abzulegen und wieder abzurufen. Wobei ich das hier nicht soweit auseinanderteilen möchte: Offensichtlich gibt es ja auch bei einem Programm mit wahlfreien Zugriff einen Adressstack, um die Unterprogramm-Aufrufe durchführen zu können und einen Datenstack, um Daten zwischen den Prozeduren übergeben zu können(der kann auch ein Queue sein).


Ich glaube wir können voraussetzen, dass es in jeder Hochsprache Datenstrukturen wie Queue und Stack gibt...




AndiE hat gesagt.:


> Eine der wichtigsten Dinge bei der OOP, selbst wenn ich mich an der Smalltalk-Syntax orientiere, ist doch, dass ein Aufruf typischerweise nicht nur einfach Präfix wie
> 
> 
> 
> ...



Ein passenderes Beispiel wäre `meth(obj, arg)` vs `obj.meth(arg)` - das ist nur ein Syntax-Unterscheid, Objekt-Orientiert oder Prozedural kann aber beides sein.
Ein Beispiel hab ich extra genannt mit Java+Lombok. Damit lassen sich vollkommen prozedurale Aufrufe von statischen Methode in dem ""OO-Stil" aufrufen: `sort(int[] array)` lässt sich dann statt `sort(ints)` als `ints.sort()` aufrufen. Beides gegensätzliche Syntax, obwohl es identisch ist.



AndiE hat gesagt.:


> Auf den ersten Blick ist das bei der OOP zwar mehr Schreibarbeit, aber es bringt mir Sicherheit. Im übertragenen Sinne kann ich doch bei der PP sagen "Ich bin hier mitten im Wald und kaufe mir ein Brot". Bei der OOP dagegen habe ich "Bäcker, gib mir ein Brot".


Ja, aber der Unterschied kommt doch nicht durch die Syntax, sondern durch das Konzept dahinter.
Und wenn man drüber diskutiert, sollte man nicht mit der (quasi beliebigen) Syntax argumentieren, sondern mit dem Konzept.
Typsicher sind beide Varianten gleichermaßen.
Und ob man jetzt schreibt gibMirBrot(Bäcker) oder Bäcker.gibMirBrot() ist auch egal - in beiden Fällen brauche ich eine Bäcker-(Objekt|Type), und eine Methode, deren Interna ich nicht kenne, wird ausgeführt. Der wesentliche Unterschied liegt woanders 



AndiE hat gesagt.:


> Ich gehe übrigens nicht mit der Aussage des 1. Posts mit, dass Vererbung keine OOP ist.


Vererbung ist keine OOP ist eine völlig andere Aussage als OOP hat Vererbung. Nur der zweiten Aussage wurde widersprochen.
Und ja, es gibt genügend OO-Sprachen, die keine Vererbung haben.


----------



## AndiE (24. Jun 2018)

Lasst uns noch mal zum Stack zurückkommen, und nehmen wir mal an, ich benötige einen Integer-Stack von einer Tiefe von 8. Rein prozedural würde ich zwar ein Modul "stack" meinem Programm hinzufügen. Dann müsste ich doch als erstes den notwendigen Speicherplatz besorgen, also allokieren. Dabei bekomme ich die Adresse, wo mein Stack im Speicher losgeht. Dann würde je nach Sprache so etwas wie Zeigerarithmetik kommen, mit deren Hilfe ich auf die Speicherplätze zugreifen kann, um so das Stackverhalten zu bekommen. Auch wenn ich das mit Funktionen kapsele, müsste ich doch immer als Argument den Adresspunkt aufrufen, wo der allokierte Speicher losgeht.
Alternativ kann ich aber auch ein OOP-Modul laden, das dann als Blaupause für ein Objekt steht, das ich mit einer nachricht instanzieren kann. Ja nach Syntax kann ich dann dem Objekt Nachrichten schicken, wie groß der Stack sein soll und dass ich Daten abrufen will. Hier kann ich nach der Instanzierung direkt auf mein Datenobjekt zugreifen.

Der Unterschied zwischen diesen beiden Modulen besteht für mich darin, dass ein PP-Modul eine Reihe von Methoden enthält aber selbst nichts im Speicher tut. Bei einem OOP-Modul wird nun aber ein Objekt als Abbild der im Modul gemachten Deklarationen angelegt, das auch gleich den notwendigen Speicherplatz belegt.

Nun gibt es aber auch noch was dazwischen, das ich im Perl-Umfeld als IOP(indirekte objektorientiere Programmierung)  kennengelernt habe. Dazu erkläre ich mal, dass jedes Programm einen Startpunkt hat. Scriptsprachen fangen meist am Anfang an, andere nach einer Main-Funktion. rein PP erfolgen nun eine Reihe strukturiert angelegter Funktionsaufrufe. Rein OOP-mäßig dagegen würde man ein Objekt anlegen und in diesem eine Startfunktion aufrufen, wenn man es nicht schon beim Anlegen startet(mach ich nicht gerne). Leider machen das nicht alle Programmierer. Stattdessen entwickeln sie hinter dem Einsprungspunkt eine Hauptprozedur, wobei sie aber (vorgegebene) Objekte implementieren und deren Methoden als Funktionen nutzen. Das ist also im Prinzip ein Misch-Masch aus PP und OOP.

PS: Ich beziehe mich bei meinen Beiträgen auf Erfahrungen mit C ,C++, C#, Forth, (etwas)Modula, (etwas )Pascal( auch mit OOP), Java, Perl(auch mit OOP) und etwas (Linux)-Shell. Ruby und Python sind mir so gut wie nicht geläufig. Natürlich ist das nur ein verschwindend geringer Anteil der vorhandenen Programmiersprachen.


----------



## mihe7 (24. Jun 2018)

@AndieE Ja, man hat bei PP sozusagen "lose Kopplung" zwischen Algorithmen und Daten. Das was Du als "Misch-Masch" aus PP und OOP beschreibst, nenne ich PP im OO-Gewand. Die Fälle sind leider oftmals sehr subtil und führen zu unerwünschten Abhängigkeiten.


----------



## mrBrown (24. Jun 2018)

AndiE hat gesagt.:


> Lasst uns noch mal zum Stack zurückkommen, und nehmen wir mal an, ich benötige einen Integer-Stack von einer Tiefe von 8. Rein prozedural würde ich zwar ein Modul "stack" meinem Programm hinzufügen. Dann müsste ich doch als erstes den notwendigen Speicherplatz besorgen, also allokieren. Dabei bekomme ich die Adresse, wo mein Stack im Speicher losgeht. Dann würde je nach Sprache so etwas wie Zeigerarithmetik kommen, mit deren Hilfe ich auf die Speicherplätze zugreifen kann, um so das Stackverhalten zu bekommen. Auch wenn ich das mit Funktionen kapsele, müsste ich doch immer als Argument den Adresspunkt aufrufen, wo der allokierte Speicher losgeht.


Oder: ich rufe eine Prozedur auf, die newStack heißt, übergebe der die Länge, und bekomme einen `stack` zurück, und rufe dann mit dem `push(stack, 1)` auf, um etwas auf den Stack zu legen. Nichts mit direkter Zeigerarithmetik oder Adressen oder ähnlichem 



AndiE hat gesagt.:


> Alternativ kann ich aber auch ein OOP-Modul laden, das dann als Blaupause für ein Objekt steht, das ich mit einer nachricht instanzieren kann. Ja nach Syntax kann ich dann dem Objekt Nachrichten schicken, wie groß der Stack sein soll und dass ich Daten abrufen will. Hier kann ich nach der Instanzierung direkt auf mein Datenobjekt zugreifen.


vs in OO: `[Stack alloc]`, womit man erstmal nur Speicher hat, den man noch initialisieren muss, damit man irgendwas machen kann: `Stack *stack = [[Stack alloc] initWithSize:5]`. Und das ganze gibt mir einen Zeiger zurück, an den man dann Nachrichten schicken kann: `[stack push:1]`

Wie gesagt: die Unterschiede, die du aufführst, sind im wesentlichen Unterschiede zwischen Sprachen und Implementierungen, aber nicht den Konzepten 

Die relevanten Konzepte merkt man bei solchen Vergleichen noch überhaupt nicht, weshalb ich sie eigentlich für ziemlich ungeeignet halte, um irgendwen von OOP zu überzeugen (ich bin allerdings völlig pro OOP)


----------



## AndiE (25. Jun 2018)

Wir reden hier aneinander vorbei, denke ich. Bei der PP habe ich doch an primitiven Datentypen: Charakter, Festzahl, Fließkommazahl. Komplexere Datentypen sind dann Arrays, Zeichenketten und Sammlungen von anderen Daten in einem Gebilde(Struct oder Record), denen aber die primitiveren Daten zu Grunde liegen. Ich habe versucht, das ziemlich allgemein zu halten, um das Konzept dahinter zu zeigen, wie ich es verstehe. Die Anwendung von Zeigern, die auf die Adresse von Variablen zeigen, ist nicht in allen PP-Konzepten gegeben, aber ich sage mal, er soll dazu gehören. Und hier habe ich dann den Fall, dass bei einem Aufruf "stack=newIntStack(5)" die Variable stack ein Zeiger auf ein int ist(int* stack). Natürlich kann dieses Verhalten für den Endprogrammierer im Verborgenen sein, aber konzeptionell geht es bei einem PP nicht anders.
Diese Aufrufmethode beim OOP ist mir noch nicht untergekommen. Ich kenne das so, dass man mit dem Schlüsselwort "new" das Objekt so anlegt, dass man damit dann arbeiten kann. Oft musste man mit "delete" hinterher auch aufräumen, wenn kein Garbage Collector vorgesehen war. Übrigens gibt das Schlüsselwort "new" eine Referenz auf das angelegte Objekt zurück. Und mit dieser Referenz( Stack* stack) kann ich dann arbeiten, indem ich die Methoden dieses Objektes als Nachrichten aufrufe.

Ich bin übrigens auch voll OOP und ärgere mich, wenn Leute im Studium und Ausbildung mit IOP (PP in OOP) arbeiten, was ich weiter oben erläutert habe. 

Und die Konzepte, die hier angezweifelt werden, kann und sollte man auch bei kleinsten Programmen anwenden. So wie es BlueJ tut. Hier im Forum sehe ich bei SWT und Swing immer wieder Erweiterungen von JFrame, in der dann auch die Main-Methode ist. Das mag funktionieren, eine Anwendung der Regeln der OOP ist es nicht. Ebenso eben der Taschenrechner. Ich muss schon bei solch kleinen Dingen mal überlegen, dass jedes Ding ein Objekt ist, also auch die Zahlen. Und bei sowas läßt sich doch auch der Nachrichtenaustausch viel besser verstehen.


----------



## mrBrown (25. Jun 2018)

AndiE hat gesagt.:


> Wir reden hier aneinander vorbei, denke ich. Bei der PP habe ich doch an primitiven Datentypen: Charakter, Festzahl, Fließkommazahl. Komplexere Datentypen sind dann Arrays, Zeichenketten und Sammlungen von anderen Daten in einem Gebilde(Struct oder Record), denen aber die primitiveren Daten zu Grunde liegen.


Ist das in OOP groß anders? Objekte bestehen aus primitiveren Objekten, die wiederum aus primitiveren Objekten bestehen (also, von Methoden abgesehen.)
(Java Objekte sind im Speicher nicht großartig anders als Structs, im wesentlichen nur primitive Datentypen, Arrays und Zeiger auf andere Objekte.)



AndiE hat gesagt.:


> Die Anwendung von Zeigern, die auf die Adresse von Variablen zeigen, ist nicht in allen PP-Konzepten gegeben, aber ich sage mal, er soll dazu gehören. Und hier habe ich dann den Fall, dass bei einem Aufruf "stack=newIntStack(5)" die Variable stack ein Zeiger auf ein int ist(int* stack). Natürlich kann dieses Verhalten für den Endprogrammierer im Verborgenen sein, aber konzeptionell geht es bei einem PP nicht anders.



Zeiger vs nicht Zeiger ist sicher kein Unterscheidungsmerkmal von PP vs OOP-Sprachen.
Mit deiner Begründung geht es ohne Zeiger auch konzeptionell in OOP-Sprachen nicht anders, denn auch o gut wie jede OOP-Sprache arbeitet intern mit Zeigern (nichts anderes sind Referenzen in Java.) 
Sagst ja sogar selbst im ersten Satz, dass Zeiger nicht in allen allen PP-Konzepten gegeben sind... 




AndiE hat gesagt.:


> Diese Aufrufmethode beim OOP ist mir noch nicht untergekommen. Ich kenne das so, dass man mit dem Schlüsselwort "new" das Objekt so anlegt, dass man damit dann arbeiten kann.


Ist Objective C, und ist deutlich näher an der ursprünglichen Definition von OOP, als zB Java.
Deiner Definition nach (weil man ständig mit Zeigern hantiert und es kein new gibt [gab, im Alter von 20 dann schon]), ist es dann aber wohl doch keine OOP-Sprache 




AndiE hat gesagt.:


> Und mit dieser Referenz( Stack* stack) kann ich dann arbeiten, indem ich die Methoden dieses Objektes als Nachrichten aufrufe.


*Das* ist der relevante Punkt, aber nicht ob es Zeiger gibt oder wie die Syntax beim Prozeduren/Methoden-Aufruf oder Nachrichten aussieht


----------



## AndiE (25. Jun 2018)

Wo habe ich denn geschrieben, dass das Vorhandensein der Anwendung von Zeigern den Unterschied macht? Es geht doch vielmehr um die Qualität des Zeigers. Bei einem PP-int-Stack ist der Zeiger auf den Stack ein (int* stack). Diesen würde ich mit stack=malloc(5*sizeof(int)) festlegen. Damit nicht wieder das bekannte Argument kommt, das muss für den Programmierer so nicht sichtbar sein. Die Methode um einen Wert auf den TOS zu legen müsste dann etwa als "pop(int* stack, int wert)" deklariert und mit pop(stack,10) aufgerufen werden. Das wäre dann C-Notation.

Vergleichbar würde mit OOP aber Stack* stack= new Stack(5); einen Zeiger auf eine Instanz einer Blaupause mit dem Namen Stack ergeben. Un in dieser Blaupause steht dann drin, dass die Construktor genannte Methode mit dem Namen der Blaupause einen int-Wert für die Stacktiefe bekommen kann. Um hier einen Wert auf diesen Stack zu legen, würde man einen Zuweisungsoperator "->" benutzen, und die in der Blaupause definierte Methode "pop(int wert)" als "stack->pop(10); aufrufen.(Syntax wie in C++).


----------



## mrBrown (25. Jun 2018)

AndiE hat gesagt.:


> Wo habe ich denn geschrieben, dass das Vorhandensein der Anwendung von Zeigern den Unterschied macht?


Okay, du sagtest nur, PP ohne Zeiger ist konzeptionell nicht möglich, und über OOP hast du nichts gesagt 
Aber das ist eben bei OOP genauso. 



AndiE hat gesagt.:


> Es geht doch vielmehr um die Qualität des Zeigers. Bei einem PP-int-Stack ist der Zeiger auf den Stack ein (int* stack). Diesen würde ich mit stack=malloc(5*sizeof(int)) festlegen. Damit nicht wieder das bekannte Argument kommt, das muss für den Programmierer so nicht sichtbar sein. Die Methode um einen Wert auf den TOS zu legen müsste dann etwa als "pop(int* stack, int wert)" deklariert und mit pop(stack,10) aufgerufen werden. Das wäre dann C-Notation


Nein, der Zeiger ist kein Zeiger auf int! Der Zeiger ist ein Zeiger auf `struct Stack`, das ist ein relevanter Unterschied!
Keine Ahnung, warum du jedes Mal aus meinem Stack einen int machst, das int und Stack sind zwei völlig unterschiedliche Dinge (oder wie speicherst du in deinem int die 10 Variablen?)


Um das noch mal Gegenüber zu stellen:



```
Stack* stack = [Stack alloc];
stack = [stack initWithSize:5];
[stack push:10]
```
vs:

```
Stack* stack = malloc(sizeof(Stack));
stack = initWithSize(stack, 5);
push(stack,10);
```

In beiden Fällen: Speicher allozieren.
In beiden Fällen: initialisieren.
In beiden Fällen: Methode ausführen.
Was man in beiden Fällen nicht sieht: ist Stack Objekt oder Struct? Sind alloc/malloc, initWithSize, push Messages oder Methoden?


Die Syntax ist nämlich nur Schall und Rauch - die kann in beiden Fällen identisch aussehen:

```
stack = Stack(5)
Stack.push(stack, 10)
stack.push(10)
```

In beiden Malen wird genau die gleiche Funktion ausgeführt - ist das jetzt Prozedural oder Objektorientiert? 
(Pointer gibts da btw keine  )



Und eben deshalb: die Syntax beim Aufruf ist völlig ungeeignet für einen Vergleich PP vs OOP.
Die relevanten Dinge (z.B. das von dir angesprochene mit "Blaupause") bekommt man an dieser Stelle nämlich überhaupt nicht mit.
Es gibt genügend gute Argumente für OOP, aber an dieser Stelle kommt eben keins wirklich zur Geltung - und das sage ich als absoluter OOP-Befürworter.


----------



## AndiE (26. Jun 2018)

Wenn wir an dieser Stelle wieder an die Umfrage zurückkommen, dann kann ich bei "wiki" nachlesen was für OOP nach Alan Key bedeutsam ist. Und der erste Satz ist da :"Everything ist a object". Wenn dieser Satz nicht mehr gelten soll, wie müsste er dann lauten? "Somethings are objects, something not" oder "Nothing is an objekt"? Wenn der Satz von Alan Key die OOP beschreibt, beschreit eine Umkehrung keine "reine" OOP, sondern eine PP im OOP oder eine reine PP. Von den beiden Verneinungssätzen gehe ich übrigens vom 2. aus. Dabei ist ein "String" auch immer ein "char[]", und ich kann mit Index auch auf einzelne Zeichen zugreifen. Ebenso ist ein Stack ja erstmal eine Ansammlung gleichartiger Felder, also würde ich das auch als Array anlegen. Ob ich als Endprogrammierer dieses Array mit `stack=stack(5)` anlege oder mit `int stack[5]` anlege, ist doch egal. Das ist ja der Sinn der Prozeduren, die Entwicklung von der Maschinennähe hin zu leichter Lesbarkeit zu bringen.

Beim Nachdenken ist mir aber aufgefallen, dass der Threadopener eher die erste Verneinung meint, es also sowohl Datenobjekte gibt als auch Methodenobjekte, während man Alan Key bei der klassischen OOP so versteht, dass beides zusammengehört. Und nun hält er "kombinierte Objekte" für gescheitert. So verstehe ich den Anfang und das Anliegen des Threads jetzt. 

Das würde doch bedeuten, dass sich eine "Money"-Funktionalität aus einem Objekt, dass den Betrag speichert (Slot - von Geldschlitz)und ausgibt, zusammensetzt, und einem, dass die Werte verändert(Banker). Wenn ich das jetzt weiterdenke, dann habe ich auch für das "Konto"zwei Objekte(Account und Clerk). Hier sieht man, dass die Methodenobjekte eher Menschen entsprechen, was zur Modellierung vielleicht sinnvoll sein kann. Das Problem für mich ist aber, dass in diesem Beispiel der "clerk" auch auf "slot" zugreifen kann und Geld entnehmen kann.


----------



## mrBrown (26. Jun 2018)

AndiE hat gesagt.:


> Dabei ist ein "String" auch immer ein "char[]", und ich kann mit Index auch auf einzelne Zeichen zugreifen. Ebenso ist ein Stack ja erstmal eine Ansammlung gleichartiger Felder, also würde ich das auch als Array anlegen. Ob ich als Endprogrammierer dieses Array mit stack=stack(5) anlege oder mit  int stack[5]  anlege, ist doch egal.


Auch wenn du es so machen würdest, gibt es einen ziemlichen Unterschied zwischen `stack` und `int*` und auch zwischen `string` und `char*`




AndiE hat gesagt.:


> Beim Nachdenken ist mir aber aufgefallen, dass der Threadopener eher die erste Verneinung meint, es also sowohl Datenobjekte gibt als auch Methodenobjekte, während man Alan Key bei der klassischen OOP so versteht, dass beides zusammengehört. Und nun hält er "kombinierte Objekte" für gescheitert. So verstehe ich den Anfang und das Anliegen des Threads jetzt.


Ja, darum ging's im wesentlichen die ganze Zeit.


----------



## AndiE (28. Jun 2018)

Mal ein Beispiel: Eine Möbelbaufirma betreibt drei Lager, ein Materiallager, ein Fertigteillager und ein Produktlager. Wenn ich jetzt der Idee von Knotenpunkt folge, habe ich ein einen Aufruf wie Dispatcher. Nimm("Stuhlbeine", 25). Dieser Dispatcher kann also auf alle drei Lager gleichermaßen zugreifen und Inhalte in diesen drei Lagern verändern und auch Inhalte abrufen. Was ist aber, wenn das räumlich größer ist, und die Lagerverwaltung aus drei räumlich getrennten Lagern mit drei Lagerverwaltern besteht? Dann macht es doch viel mehr Sinn, wenn die Lagerverwalter jeder über sein Lager Bescheid weiß und darüber Auskunft geben kann.

Anderes Beispiel: Für ein Ernährungsprogramm werden bei Lebensmitteln die Anteile von Kohlenhydraten, Fetten und Eiweißen je 100g und die durchschnittliche Portionsgröße gespeichert. Um jetzt auszurechnen, wie groß diese werte, z.B. bei 3 Burgern und zwei Salat ist, macht es doch Sinn, wenn Burger und Salat ihre Werte selbst ausrechnen. ergebis= salat.calgehalt+3*burger.calgehalt();

Wie kann ich das ohne OOP sonst so lösen, dass es nachvollziehbar ist.


----------



## mihe7 (28. Jun 2018)

```
struct essen { int kohlenhydrate, fett, eiweiss;  }
int calcgehalt(struct essen *v) { return (v->kohlenhydrate + v->eiweiss) * 4 + 9*v->fett; }
int ergebnis = calcgehalt(salat) + 3 * calcgehalt(burger);
```


----------



## mrBrown (28. Jun 2018)

AndiE hat gesagt.:


> Mal ein Beispiel: Eine Möbelbaufirma betreibt drei Lager, ein Materiallager, ein Fertigteillager und ein Produktlager. Wenn ich jetzt der Idee von Knotenpunkt folge, habe ich ein einen Aufruf wie Dispatcher. Nimm("Stuhlbeine", 25). Dieser Dispatcher kann also auf alle drei Lager gleichermaßen zugreifen und Inhalte in diesen drei Lagern verändern und auch Inhalte abrufen. Was ist aber, wenn das räumlich größer ist, und die Lagerverwaltung aus drei räumlich getrennten Lagern mit drei Lagerverwaltern besteht? Dann macht es doch viel mehr Sinn, wenn die Lagerverwalter jeder über sein Lager Bescheid weiß und darüber Auskunft geben kann.


Der "Dispatcher" implizier ein Objekt, und das gäbe es in PP eher nicht 

In PP wäre das einfach `nimm(materiallager, "Stuhlbeine", 25)`



AndiE hat gesagt.:


> Anderes Beispiel: Für ein Ernährungsprogramm werden bei Lebensmitteln die Anteile von Kohlenhydraten, Fetten und Eiweißen je 100g und die durchschnittliche Portionsgröße gespeichert. Um jetzt auszurechnen, wie groß diese werte, z.B. bei 3 Burgern und zwei Salat ist, macht es doch Sinn, wenn Burger und Salat ihre Werte selbst ausrechnen. ergebis= salat.calgehalt+3*burger.calgehalt();


`ergebnis = calgehalt(salat) + 3 * calgehalt(burger)`


----------



## AndiE (28. Jun 2018)

```
struct essen{ int kh;int e; int  f, int prtion};

int gehalt(struct essen* v){ //Berechnung};

main(){
struct essen burger;

burger.kh=3;
burger.e=5;
burger.f=20;
burger.size=150;

int cal=gehalt(&burger);

printf(cal);
}
```

Das mag jetzt nicht ganz genau stimmen- da bin ich etwas aus dem Training. 
In OOP(Java)

```
public class Essen{
int kh;
int e;
int f;
int size;

public Essen( int kh,int e, int f, int size){
// Werte festlegen
}

int gehalt(){
//Berechnung
}

};

public class Kalo{

public static void main(){
Essen e= new Essen (3,5,20,150); //kh,e,f,size
int cal=e.gehalt();
println(cal);
}

};
```

Für mich ist der Vorteil der 2. Version, dass in der main nur die statischen Daten deklariert, die ganze Dynamik aber in die Methoden im Essenobjekt delegiert werden. In der 1. Version habe ich das Anlegen der Daten UND deren Abarbeitung in der main und ihren Unterfunktionen. 

Im anderen Fall, der der TO wohl meint,  habe ich aber:


```
class Essen{
//Variablen
//Setter und Getter
};

class Rechne{

int gehalt(Essen e){
//Berechne
}

};

class Kalo{

main(){
Essen e= new Essen();
Rechne r= new Rechne();
int cal= r.gehalt(e);
println(cal)
}
};
```


----------



## mrBrown (28. Jun 2018)

AndiE hat gesagt.:


> Für mich ist der Vorteil der 2. Version, dass in der main nur die statischen Daten deklariert, die ganze Dynamik aber in die Methoden im Essenobjekt delegiert werden. In der 1. Version habe ich das Anlegen der Daten UND deren Abarbeitung in der main und ihren Unterfunktionen.


main aus Variante 1:

```
main(){
struct essen burger = {3,5,20,150};//kh,e,f,size
int cal=gehalt(&burger);
printf(cal);
}
```

main aus Variante 2:

```
public static void main(){
Essen e= new Essen (3,5,20,150); //kh,e,f,size
int cal=e.gehalt();
println(cal);
}
```

Da passiert nicht wirklich mehr in der einen Main, als in der anderen...


----------



## code_solution (28. Jun 2018)

@ mihe7, pm mich bitte oder schau mal in meinen thread vorbei es ist die letzte aufgabe die ich machen muss, leute kommt helft mir bitte es ist die letzte aufgabe die ich machen muss ich steh aufn schlauch, sry für off Topic aber mega wichtig <3 Für Verirrte - Fragen zu JavaScript ----> wer kann die Aufgabe lösen?


----------



## mrBrown (28. Jun 2018)

code_solution hat gesagt.:


> @ mihe7, pm mich bitte oder schau mal in meinen thread vorbei es ist die letzte aufgabe die ich machen muss, leute kommt helft mir bitte es ist die letzte aufgabe die ich machen muss ich steh aufn schlauch, sry für off Topic aber mega wichtig <3 Für Verirrte - Fragen zu JavaScript ----> wer kann die Aufgabe lösen?


Dafür musst du nicht andere Thread zuspammen.


----------



## AndiE (28. Jun 2018)

mrBrown hat gesagt.:


> Der "Dispatcher" implizier ein Objekt, und das gäbe es in PP eher nicht



Im Sinne der ersten Posts des Threadopeners würde dieser Dispatcher aber einem der Service-Objekte entsprechen, die dort mokiert wurden, also einem Objekt( also tatsächlich einem OO-Konstrukt), das aber nur Methoden enthält.

Und statt mit Sonnentemperatur und Motorleistung sind hier die Dinge etwas überschaubarer. Sicher können, Applikationen, die nach verschiedenen Mustern entwickelt werden, das Selbe machen. Daher kann man doch nicht davon Sprechen oder Schreiben, dass eines gescheitert ist.


----------



## mihe7 (28. Jun 2018)

AndiE hat gesagt.:


> Daher kann man doch nicht davon Sprechen oder Schreiben, dass eines gescheitert ist.


Was die OO betrifft, so kann man das 50 Jahre nach ihrer "Einführung" und immer noch großer Beliebtheit, wohl sowieso nur schwer behaupten. 

OT: @mrBrown zumal ich von ihm (mir unbekannt) heute das erste mal lese.


----------



## mrBrown (28. Jun 2018)

AndiE hat gesagt.:


> Im Sinne der ersten Posts des Threadopeners würde dieser Dispatcher aber einem der Service-Objekte entsprechen, die dort mokiert wurden, also einem Objekt( also tatsächlich einem OO-Konstrukt), das aber nur Methoden enthält.


Gehört denn das Lager, auf dem der Dispatcher arbeitet, zum Dispatcher (also als Instanzvariable) oder gibt es drei globale Lager (etwa static in Java) und der Aufruf findet völlig ohne Bezug zu irgendeinem Lager statt?
Ersteres wäre auch laut TO OOP.




AndiE hat gesagt.:


> Und statt mit Sonnentemperatur und Motorleistung sind hier die Dinge etwas überschaubarer.


Überschaubar heißt aber bei sowas auch oft soweit reduziert, dass die wesentlichen Dinge untergehen  
Polymorphie und Verbindung von Daten+Verhalten spielt dabei nämlich nur selten eine Rolle


----------



## mihe7 (29. Jun 2018)

Durch Kapselung wird letztlich festgelegt, welche Teile eines Stücks Software von anderen Teilen nicht benutzt werden dürfen. Das hat natürlich nichts mit OO im Speziellen zu tun und lässt sich auch in PP erreichen, sei es z. B. durch Möglichkeiten, die die Sprache bietet (z. B. Headerfiles in C), "Disziplin" oder auch durch Aufteilung in mehrere separate Programme.

In jedem Fall führt Kapselung zu einer Definition eines "Inneren" und eines "Äußeren", die über eine gemeinsame Schnittstelle zusammenhängen. Damit wird allerdings auch definiert, welche Daten und/oder welche Prozeduren irgendwie zusammengehören. Kapselung ist also kein grundsätzliches Problem in PP. 

Das sehe ich an anderer Stelle. Wir formulieren das Problem als Prozedur, die eine Eingabe bekommt und eine Ausgabe liefert. Eine Prozedur ist eine Aneinanderreihung von Anweisungen, die ihrerseits Prozeduraufrufe darstellen können. Wird das Problem zu groß, teilen wir es in kleinere Probleme (=Prozeduren) auf usw. Die Abstraktion erfolgt somit in Form von Prozeduren. Dadurch entsteht ein statischer Graph voneinander abhängiger Prozeduren.

In diesem Graph kann ich eine Dynamik während der Laufzeit nur durch entsprechende Kontrollstrukturen erreichen - der Graph steht aber zur Übersetzungszeit fest.

Dieses Manko kann ich in PP durch Funktionszeiger beheben. Dann bin ich aber m. E. dort angelangt, wo OO anfängt.


----------



## AndiE (29. Jun 2018)

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 (29. Jun 2018)

AndiE hat gesagt.:


> 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



AndiE hat gesagt.:


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



AndiE hat gesagt.:


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




AndiE hat gesagt.:


> 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 (29. Jun 2018)

AndiE hat gesagt.:


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



AndiE hat gesagt.:


> 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 (30. Jun 2018)

@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 (30. Jun 2018)

AndiE hat gesagt.:


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



AndiE hat gesagt.:


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




AndiE hat gesagt.:


> 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 (18. Jul 2018)

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



mrBrown hat gesagt.:


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





mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> 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^^





mrBrown hat gesagt.:


> und das jetzt bitte in der prozeduralen Sprache Pascal.


Du weichst meiner Aussage/Fragestellung aus.




mrBrown hat gesagt.:


> 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^^




mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


> 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



mrBrown hat gesagt.:


> 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




mrBrown hat gesagt.:


> 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!



mrBrown hat gesagt.:


> 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





mrBrown hat gesagt.:


> 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^^




mrBrown hat gesagt.:


> 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ß^^




mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> 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^^




mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> 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



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> 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


----------



## mihe7 (18. Jul 2018)

knotenpunkt hat gesagt.:


> Und sollte OO das A und O sein



Nein. Choose the right tool for the job.



knotenpunkt hat gesagt.:


> Und es zeigt auch schon hier die damit zusammenhängend auftreten werdenden Nebeneffekte:
> Flexibilitätseinbußen!



Zu viel Flexibilität ist ein Problem. Beispiel: "wir nehmen XML/XLS/CSV/JSON für den Datenaustausch" - super flexibel - und nu?


----------



## AndiE (18. Jul 2018)

@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 (18. Jul 2018)

knotenpunkt hat gesagt.:


> @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 
Wo hab ich denn Bezug auf ein ganze anderes Thema genommen?



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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




knotenpunkt hat gesagt.:


> 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 



knotenpunkt hat gesagt.:


> 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!



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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


knotenpunkt hat gesagt.:


> 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 ^^



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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





knotenpunkt hat gesagt.:


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




knotenpunkt hat gesagt.:


> 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 (24. Jul 2018)

Hey,



mrBrown hat gesagt.:


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





mrBrown hat gesagt.:


> 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^^




mrBrown hat gesagt.:


> 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?!^^



mrBrown hat gesagt.:


> Für mich ist das das Ende der Katastrophe...kommt auf die Sichtweise an


ja^^ (das ja ist jetzt keine Zustimmung^^)



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> *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?!^^





mrBrown hat gesagt.:


> 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^^






mrBrown hat gesagt.:


> 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 (24. Jul 2018)

knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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




knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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 




knotenpunkt hat gesagt.:


> Jetzt habe ich mal wieder ein praktisches Beispiel:


Dazu schreib ich gleich was


----------



## Xyz1 (24. Jul 2018)

knotenpunkt hat gesagt.:


> 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 (24. Jul 2018)

mrBrown hat gesagt.:


> 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 (25. Jul 2018)

knotenpunkt hat gesagt.:


> 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





knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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


----------



## Xyz1 (25. Jul 2018)

Meniskusschaden hat gesagt.:


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


Meniskusschaden hat gesagt.:


> 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 (25. Jul 2018)

DerWissende hat gesagt.:


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



DerWissende hat gesagt.:


> Sehr blauäugig, bei Nicht-OO-Projekten von einer geringeren Qualifikation zu sprechen....


Hat er nicht.


----------



## Xyz1 (25. Jul 2018)




----------



## knotenpunkt (26. Jul 2018)

Hey,



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


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





mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> 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^^





mrBrown hat gesagt.:


> 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^^





mrBrown hat gesagt.:


> 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^^




mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


> 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^^





mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> Dazu schreib ich gleich was


Darauf werde ich dort dann später noch antworten^^



mrBrown hat gesagt.:


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


Nur Informatik^^



mrBrown hat gesagt.:


> 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 (26. Jul 2018)

knotenpunkt hat gesagt.:


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


```
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: 

```
interface PostPolicy {
    boolean canPost(...);
}
```

Der Code oben ändert sich damit zu:

```
if (policy.canPost(...)) {
}
```

Die Policy könnte z. B. per DI injected werden:

```
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 (26. Jul 2018)

knotenpunkt hat gesagt.:


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

```
{
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...



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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




knotenpunkt hat gesagt.:


> 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 ^^


knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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




```
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^^)



knotenpunkt hat gesagt.:


> 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 (26. Jul 2018)

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.


----------



## Meniskusschaden (27. Jul 2018)

knotenpunkt hat gesagt.:


> Wie ich SQL an der Stelle liebe.


Nur schade, dass du es nicht verwenden darfst, weil du ja keine Programmierparadigmen vermischen willst. Oder gilt das Verbot nur für OO-Programmierer?


knotenpunkt hat gesagt.:


> also ich finde schon, dass man entweder 100%iges OO programmieren sollte, oder gar nicht.


----------



## knotenpunkt (2. Aug 2018)

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.





mrBrown hat gesagt.:


> 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^^



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> Aber Prozeduren (und damit auch Structs?) siehst du als einzelne Module an?


Ich glaube da haben wir uns etwas verhettert^^



mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> DATEN, bei OO injectest du Daten UND FUNKTIONEN auf diesen. Genau darum geht es doch.


und was machen diese FUNKTIONEN?^^



mrBrown hat gesagt.:


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





mrBrown hat gesagt.:


> 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 (2. Aug 2018)

httpdigest hat gesagt.:


> 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 (2. Aug 2018)

knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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


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.




knotenpunkt hat gesagt.:


> Du möchtest folgenden Batch-Prozess ausführen.
> 
> k;
> for(-> 100k)
> ...


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.




knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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()?



knotenpunkt hat gesagt.:


> 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 



knotenpunkt hat gesagt.:


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


der lokale Zustand?



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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


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.



knotenpunkt hat gesagt.:


> 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 (2. Aug 2018)

knotenpunkt hat gesagt.:


> 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" 



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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 (2. Aug 2018)

knotenpunkt hat gesagt.:


> 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 (27. Aug 2018)

hey,



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


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



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?




mrBrown hat gesagt.:


> 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




mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> 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^^




mrBrown hat gesagt.:


> der lokale Zustand?


das musste mir näher erklären, also was du damit meinst.



mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


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



mihe7 hat gesagt.:


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




mihe7 hat gesagt.:


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



AndiE hat gesagt.:


> 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 (27. Aug 2018)

knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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 (27. Aug 2018)

knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> Ein Switch-Case geht jetzt etwas in die Richtung fixer Konfigurationsstate





knotenpunkt hat gesagt.:


> Und das ist für mich hochdynamisch


Der Widerspruch fällt dir schon so ein bisschen auf?



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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 (27. Aug 2018)

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.


----------



## AndiE (12. Sep 2018)

Geht es hier noch weiter?


----------



## knotenpunkt (18. Okt 2018)

hey,



AndiE hat gesagt.:


> Geht es hier noch weiter?



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



mihe7 hat gesagt.:


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



mihe7 hat gesagt.:


> 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!





mihe7 hat gesagt.:


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




mrBrown hat gesagt.:


> 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^^





mrBrown hat gesagt.:


> 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!^^




mrBrown hat gesagt.:


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







mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> 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!




AndiE hat gesagt.:


> 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 (18. Okt 2018)

knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



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



knotenpunkt hat gesagt.:


> 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!




knotenpunkt hat gesagt.:


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





knotenpunkt hat gesagt.:


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




knotenpunkt hat gesagt.:


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


knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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 (18. Okt 2018)

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 (18. Okt 2018)

knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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 (18. Okt 2018)

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 (19. Okt 2018)

knotenpunkt hat gesagt.:


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


knotenpunkt hat gesagt.:


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

```
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 (21. Nov 2018)

hey,



mrBrown hat gesagt.:


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





mrBrown hat gesagt.:


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





mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> 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!





mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


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



mihe7 hat gesagt.:


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


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.



AndiE hat gesagt.:


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



Meniskusschaden hat gesagt.:


> 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 (21. Nov 2018)

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 (21. Nov 2018)

knotenpunkt hat gesagt.:


> Meniskusschaden hat gesagt.:
> 
> 
> > 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.
> ...


Nein, leider nicht. Hier:


knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> @Meniskusschaden
> zu deinem Code:
> 
> Das ist ungefähr das pentadent hierzu:
> ...


Nein, ich erkenne da keinen Zusammenhang zu meinem Beispiel.



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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


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 (22. Nov 2018)

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



knotenpunkt hat gesagt.:


> 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 (22. Nov 2018)

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


----------



## Xyz1 (22. Nov 2018)

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

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


----------



## Thallius (22. Nov 2018)

Doch ich...


----------



## mrBrown (24. Nov 2018)

knotenpunkt hat gesagt.:


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


knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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


----------



## knotenpunkt (7. Mai 2019)

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^^





AndiE hat gesagt.:


> Die Änderung der Zugriffe wird nur durch Änderung der Tupel eingerichtet.


Ich habe doch eine Datenbank erwähnt. Wo ist da jetzt der Unterschied?





Meniskusschaden hat gesagt.:


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



Meniskusschaden hat gesagt.:


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




Meniskusschaden hat gesagt.:


> 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




Meniskusschaden hat gesagt.:


> 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^^




Meniskusschaden hat gesagt.:


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





mrBrown hat gesagt.:


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


VERWENDEN Polymorphie bzw. bauen auf Polymorphie auf.




mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> * 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



mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


> Abgesehen von meiner Skype-Abneigung gern


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 (7. Mai 2019)

knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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 (7. Mai 2019)

hey,



mrBrown hat gesagt.:


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






mrBrown hat gesagt.:


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




mrBrown hat gesagt.:


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



mrBrown hat gesagt.:


> Ist wirklich untergegangen, ich guck gleich mal


Hast dus' bereits gefunden?^^


lg knotenpunkt


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


----------



## mrBrown (7. Mai 2019)

knotenpunkt hat gesagt.:


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





knotenpunkt hat gesagt.:


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




knotenpunkt hat gesagt.:


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


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:


```
BanConditions conditions;

ban_user(WER,WEN,wievielUhrHabenWirgerade, weitereParameter)
{
if(conditions.allMatch(WER,WEN,wievielUhrHabenWirgerade, weitereParameter)) //ob überhaupt
....
```
und zb 
	
	
	
	





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



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


> 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").



knotenpunkt hat gesagt.:


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



knotenpunkt hat gesagt.:


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


----------



## mihe7 (8. Mai 2019)

knotenpunkt hat gesagt.:


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


Das ist doch genau der Punkt: Polymorphie (im Sinne des dynamic dispatch) ist kein Bestandteil des prozeduralen Paradigmas. Natürlich kannst Du in PP-Sprachen Polymorphie über Function Pointer herstellen, dann programmierst Du aber an genau dieser Stelle mit ziemlicher Sicherheit nicht mehr prozedural. Umgekehrt gilt das Gleiche: ich kann z. B. objekt-orientiert Objekte rumreichen, in den Methoden aber prozedural programmieren.


----------



## knotenpunkt (20. Mai 2020)

hey @mrBrown,

hab dir auf Discord (dort scheinst du gerade etwas inaktiv zu sein) und hier im Forum über PN geschrieben.
Eventuell hast du ja in nächster Zeit mal lust mit mir gerade über diese Thematik hier in diesem Thread etwas zu voicen.
Lag in der Vergangenheit auch immer ein wenig an mir, dass das bislang nicht wirklich zustande kam. Hab das in letzter Zeit nicht ganz so zielstrebig verfolgt.

lg knotenpunkt


----------



## mihe7 (20. Mai 2020)

Bis @knotenpunkt mit dem Thema halbwegs durch ist, wird das nächste Paradigma erfunden


----------



## knotenpunkt (20. Mai 2020)

mihe7 hat gesagt.:


> Bis @knotenpunkt mit dem Thema halbwegs durch ist, wird das nächste Paradigma erfunden


Da hätte ich nichts dagegen^^
Hoffentlich dann ein wesentlich besseres Paradigma als OO^^

lg knotenpunkt


----------



## mihe7 (20. Mai 2020)

OO++


----------



## White_Fox (21. Mai 2020)

mihe7 hat gesagt.:


> Bis @knotenpunkt mit dem Thema halbwegs durch ist, wird das nächste Paradigma erfunden


Ich bin ja mal auf den weiteren Threadverlauf gespannt. Mal sehen, was @knotenpunkt seit 2018 an Erfahrung dazugewonnen hat...


----------



## mihe7 (21. Mai 2020)

Ich habe mir den ganzen Thread nochmal durchgelesen und wüsste ehrlich gesagt nicht, was da noch als Argument kommen könnte. Aber wer weiß, bis zur Rente haben wir ja noch etwas hin


----------



## White_Fox (21. Mai 2020)

Ich meinte eher: Vielleicht findet er OOP mittlerweile richtig gut.

Es kamen ja bisher so einige abstruse Beispiele (z.B. das mit der Sonne und dem Motorad), wo das Beispiel selber eigentlich schon zeigt wo der Denkfehler liegt (und was man mit OOP ausmerzen wollte).


----------



## advanced_java (21. Mai 2020)

mihe7 hat gesagt.:


> Ich habe mir den ganzen Thread nochmal durchgelesen


Langeweile? 🤣


----------



## mihe7 (21. Mai 2020)

Nein, tatsächlich habe ich es auch nur überflogen


----------

