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.
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
wäre doch viel besser.
pseudo-OO mit einer weiteren ServiceKlasse könnte dann wie folgt aussehen:
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
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
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.
Code:
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
Code:
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
}
pseudo-OO mit einer weiteren ServiceKlasse könnte dann wie folgt aussehen:
Code:
class EmailanbieterANDLoggerServiceDeciderService
{
public sendMail(Emailnachricht)
{
extrahiere aus Emailnachricht und time() -> LoggerServiceKlasseX und EmailanbieterDataX
new EmailService(LoggerServiceX, EmailanbieterDataX).sendMail(Emailnachricht);
}
}
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
Code:
new EmailService(LoggerServiceX, EmailanbieterDataX, null).sendMail(Emailnachricht);
//wobei null member4 abdeckt
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