Java...



  • 1.) Mein Design/Programmierstil ist nicht auf gute Debugmoeglichkeiten ausgelegt.
    2.) Mein Design ist nicht auf Testen ausgelegt.

    Mein Design ist problembezogen mit etwas Spielraum. Durch einfache Richtlinien wie Entkoppeln ist die Software meist gut zu testen und zu debuggen. Aber trotzdem wuerde ich nie mit testen/debuggen argumentieren. Es sind nur Nebenerscheinungen.

    Was mich an DI stoert ist, dass selbst ein Parameter im Konstruktor schon als DI gilt, es alles und nichts sein kann. Toll dass die OOP-Leute dafuer ein Begriff gefunden haben, was gesunder Menschenverstand von eh her macht. Genau wie SOA - Same old Architekture. Es ist einfach der alte Scheiss nur mit neuen Buzzwords. Deswegen spricht nix gegen DI, weils alle vorher schon so gemacht haben, es nur nicht benennen konnten.



  • volkard:
    Wenn Du nicht mit Unregistrierten diskutieren möchtest, nehme ich die Frage gerne auf:

    Mal ein Anwendungsbeispiel:
    Habe hier eine Domänenschicht, also einen komplexen Klassenverband, welcher meine Anwendungsdomäne abbildet.
    Darauf basierend eine Prozessschicht, welche Use-Cases auf Basis der Domäne implementiert.
    Diese wiederrum nutzt eine Persistenzschicht.
    Ganz oben gibt es Webdienste, welche auf Basis der Prozessschicht Anwendungsdienste bereitstellen.
    Querschnittsfunktionen (Logging, Transformationen, Sicherheitsaspekte etc.) implementiere ich in einer Infrastrukturschicht, die jede andere Schicht verwenden darf.

    Mit DI kann ich nun automatisch hierarchisch Abhängigkeiten in den jeweiligen Konstruktor binden lassen, d.h.:
    Die Persistenzschicht erhält über den Konstruktor automatisch Kontextinformationen (Datenbankumgebung etc.), der Prozessschicht werden automatisch die Persistenzschicht-Abhängigkeiten zugewiesen, den wichtigen Klassen wird per Konstruktor eine Protokollierungsmöglichkeit gegeben usw.

    Bei Modultests kann ich die ganzen Abhängigkeiten dann sehr einfach durch Mock-Objekte ersetzen, weil ich sie ja einfach im Konstruktor übergeben kann. Oder ich lass wieder alles per DI machen und ändere nur meine Konfiguration ab.

    Welche Vorteile bietet C++, welche mir gegenüber DI diese Dinge vereinfachen? Meines Erachtens könnten sie kaum perfekter gelöst werden.

    Da gibt es eine Menge Schichten, die für Geschäftsanwendungen mit Datenbankzugriff auch Sinn ergeben. Das Architekturmodell halte ich nicht für java-spezifisch.

    Die zwei Fragen verbleiben also:

    1. Wie würde man das in C++ lösen? Überall alle Referenzen übergeben wäre mein Weg, ich verstehe aber, dass DI von Java das vereinfacht (zumal wenn man Objekterzeugung und Referenzübergabe trennt, sodass man noch Setter einbauen muss *schauder* Ist zum Beispiel nötig, wenn ich ein UI-Framework wie QT nehme, bei dem automatisch ein bestimmter ctor aufgerufen wird)
    2. Angenommen, Du sagst, dieses Schichtenmodell ist java-spezifisch. Wie würdest Du eine entsprechende Anwendung dann in C++ aufbauen?


  • Naja für DI gibt es vermutlich keine scharfe Begriffsdefinition. Allerdings zählt dazu schon etwas mehr als Parameterübergabe im Konstruktor, zumindest an dem, was gängige DI Frameworks so können.

    z.B. die zentrale Definition und Verwaltung von Lebenszyklen. Wenn ich ein ORM nutze und dafür eine ORM-Session in einer Webapplikation pro Request nutzen will, sodass ich während der Requestverarbeitung mit Transaktionen hantieren kann ohne mir groß über den jeweiligen Aufrufkontext Gedanken machen zu müssen, kann ich z.B. in Castle Windsor (DI-Framework) einfach den Lebenszyklus der ORM-Abhängigketein auf "Per Request" setzen. Mir wird eine deklarative Verwaltung meiner Abhängigkeiten gestattet und das nimmt viel Arbeit ab.

    Ich würde ein paar Klassen mit Abhängigkeitsübergabe im Konstruktor nicht als DI bezeichnen und wüsste auch sonst niemanden, der das tut...



  • Ja, DI kann mehr, das habe ich mittlerweile auch verstanden. Aber das Pendant in C++ dazu wäre eben bisher nur die Referenzübergabe. Und da hat Java (verstanden als Sprache + Bibliotheken) eben einen Vorteil - den volkard aber verneint, sodass mich interessieren würde, wie er das begründet.



  • @Eisflamme: Sorry, das Posting war für knivil...



  • Leider ist meine Erfahrung mit Webapplikationen oder Datenbanken nicht existent. Aber mit embedded, KI und wissenschaftlichem Rechnen kann ich dienen. GUIs kriege ich auch hin.



  • ich bin auch in den eher theoretischen bereichen der informatik wie mustererkennung oder algorithmische geometrie zuhause, würde aber dennoch nicht die mir aus der praxis unbekannten dinge als "same old story" abstempeln...



  • dto-depp schrieb:

    würde aber dennoch nicht die mir aus der praxis unbekannten dinge als "same old story" abstempeln...

    Ich habe keine Erfahrung bzgl. deines konkreten Beispiels. Aber ich kenne Designpatterns und Architekturmuster. Auch wenn ich keine Erfahrung mit Sessionmanagment habe, so habe ich dennoch Software mit mehreren Schichten geschrieben. Es haut mich aber nicht aus dem Hocker, wenn da von Multi-Tier- Multi-Layer- Multi- ... gesprochen wird. Haben andere und frueher auch schon so gemacht ... so what's the point?



  • Moment, es geht doch gerade um die Frage, wie man die Vorteile, die man bei Java durch DI hat, in C++ reproduzieren würde, oder? Die Vorteile erscheinen gerade einfache und flexible Integration von Abhängigkeiten, für die man keinen extra Code schreiben muss. Das scheint ja die Übersichtlichkeit innerhalb der Klasse zu erhöhen. Lebenszeitverwaltung könnte ein Vorteil sein, aber das kann man vermutlich günstiger mit einem shared_ptr oder so in C++ abdecken.

    Hm... wobei: wo genau ist denn der Vorteil, wenn man alles in den Header via Annotation schreibt statt einfach ein Attribut zu haben und das dann über Setter/ctor zu übergeben? Man spart sich etwas Schreibarbeit, okay. Aber ist das viel?

    Was wären weitere Vorteile?



  • Vorteile, die man bei Java durch DI hat

    Das ist sehr subjektiv. Man kann auch jede Schicht/Teilsystem als Service implementieren und Nachrichten samt Kontext hin- und herschicken. Dann gibt es nur Abhaengigkeiten zu den einzelnen Messagequeues, die dem Konstruktor der Schicht/Teilsystem/Modul als Parameter uebergeben werden. Im Extremfall gibt es nur eine Messagequeue fuer alle Teilsysteme. Nun, hier injiziere ich die Abhaengigkeit zur Messagequeue. Warum? Na weil sie von mehreren Teilsystemen benutzt wird, sollte sie keinem einzelnen Teilsystem zugeordnet werden. D.h. es ist ein Ding fuer sich. Das klingt vernuenftigt. Und Menschen waren lange vor dem Begriff DI schon vernueftig.

    Wenn man im Inet nach DI sucht: http://stackoverflow.com/questions/130794/what-is-dependency-injection

    "Dependency Injection" is a 25-dollar term for a 5-cent concept. [...] Dependency injection means giving an object its instance variables. [...].

    Suuuper. Um deine Frage neu zu formulieren: Was ist der Vorteil, dem Konstruktor Parameter/Objekte mitzugeben?



  • Daher versuche ich es ja zu objektifizieren, indem ich nach Vorteilen von Java-DI frage. Ich selbst nutze Java nicht, kann mir aber vorstellen, dass es Projekte, wie das obige Beispiel mit den Schichten, gibt, in denen das hilfreich ist.



  • knivil schrieb:

    Suuuper. Um deine Frage neu zu formulieren: Was ist der Vorteil, dem Konstruktor Parameter/Objekte mitzugeben?

    1. Muss man sie mit einem DI-Container nicht selbst angeben, und kann in einer Konfiguration (die in einer Datei oder im Code etc. steht) die Abhängigkeiten austauschen.
    2. Die Gleichen Vorteile die man beispielsweise mit dem Strategiemuster auch hat: Man kann leicht das Verhalten ändern.

    Das wesentliche Ziel ist aber die Abhängigkeiten in Schnittstellen herauszulösen. Sei es nun zur besseren Wartbarkeit, sei es nun weil z.B. Lizenzabhängig ein unterschiedlicher Funktionsumfang freigeschaltet werden soll, sei es um eine Komponente unabhängig für sich zu testen, sei es um diesen Mechanismus auch für ein Pluginsystem zu verwenden (z.B. wenn ein Konstruktor eine Collection von allen Registrierten Elementen einer bestimmten Art übergeben bekommt)...

    Grundsätzlich müssen es aber nicht zwangsläufig Konstruktorparameter sein (es gibt noch mehr Möglichkeiten).



  • Kellerautomat schrieb:

    allweare schrieb:

    In Java die Fibonaccizahlen ausgeben, sollte mit 10 Zeilen leicht gehen. In C++ brauchen erfahrene Programmierer schon mal 40 oder mehr Zeilen ➡ http://www.c-plusplus.net/forum/311250

    https://ideone.com/fdaWg7

    Du bis halt noch kein erfahrener C++ Programmierer.



  • Nun, die Frage war leicht ironisch gestellt. Wenn ich Objekte als Parameter habe und Objekte Daten+Verhalten sind, dann kann ich Verhalten nicht nur durch Werte parametrisieren sondern auch durch Verhalten anderer Objekte.



  • Kellerautomat schrieb:

    allweare schrieb:

    In Java die Fibonaccizahlen ausgeben, sollte mit 10 Zeilen leicht gehen. In C++ brauchen erfahrene Programmierer schon mal 40 oder mehr Zeilen ➡ http://www.c-plusplus.net/forum/311250

    https://ideone.com/fdaWg7

    Es geht kürzer:

    std::vector<int> v(30, 1); //na gut, unnötig, aber was solls
    
        std::adjacent_difference(v.begin(), v.end() - 1, v.begin() + 1, std::plus<int>());
    
        std::copy( v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ", ") );
    


  • allweare schrieb:

    Kellerautomat schrieb:

    allweare schrieb:

    In Java die Fibonaccizahlen ausgeben, sollte mit 10 Zeilen leicht gehen. In C++ brauchen erfahrene Programmierer schon mal 40 oder mehr Zeilen ➡ http://www.c-plusplus.net/forum/311250

    https://ideone.com/fdaWg7

    Du bis halt noch kein erfahrener C++ Programmierer.

    Die Lösung von Werner Salomon ist auch ein wenig Overkill.



  • Sone schrieb:

    Es geht kürzer:

    std::vector<int> v(30, 1); //na gut, unnötig, aber was solls
    std::adjacent_difference(v.begin(), v.end() - 1, v.begin() + 1, std::plus<int>());
    std::copy( v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ", ") );
    

    Geht das auch ohne dieses unnötige ", " am Schluss?



  • Sone schrieb:

    Kellerautomat schrieb:

    allweare schrieb:

    In Java die Fibonaccizahlen ausgeben, sollte mit 10 Zeilen leicht gehen. In C++ brauchen erfahrene Programmierer schon mal 40 oder mehr Zeilen ➡ http://www.c-plusplus.net/forum/311250

    https://ideone.com/fdaWg7

    Es geht kürzer:

    std::vector<int> v(30, 1); //na gut, unnötig, aber was solls
    
        std::adjacent_difference(v.begin(), v.end() - 1, v.begin() + 1, std::plus<int>());
    
        std::copy( v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ", ") );
    

    Höh? Deine Lösung ist deutlich länger.

    Edit: Okay, den Kommentar entfernt. Immer noch länger.



  • Aber, Ethon, doch nicht nach Zeichen, nach signifikanten Zeilen! (Nach Zeichen wäre natürlich was anderes)



  • Anzahl Zeilen, Ok:

    #include <algorithm>
    #include <iostream>
    #include <vector>
    int main(){std::vector<int> v(30);v[0] = 1;std::adjacent_difference(v.begin(), v.end() - 1, v.begin() + 1, [](int a, int b) {return a + b;});for(int i : v)std::cout << i << ", ";}
    

    Winner! :p


Anmelden zum Antworten