Auf Interface Programmieren



  • Hallo Leute,

    ich habe mal eine Frage. Ich habe mal wo gelesen das man immer auf ein Imterface Programmieren soll und nicht auf eine Implementierung.

    Wäre das hier der richtige Ansatz ? Vorteil ist halt wenn ich am IManager was machen muss dann brauch ich das nur einmal im BaseManager Implementieren und alle Konkreten Manager hätten diese Methoden auch.

    class IManager {
    
    public: 
    
    	virtual void Init() = 0;
    	virtual void Update() = 0;
    	virtual void Render() = 0;
    };
    
    class BaseManager : public IManager {
    
    public:
    
    	BaseManager(){};
    	virtual ~BaseManager(){};
    
    	virtual void Init() {
    		// Basis Implementierung für Init
    	}
    
    	virtual void Update() {
    		// Basis Implementierung für Update
    	}
    
    	virtual void Render() {
    		// Basis Implementierung für Render
    	}
    };
    
    class KonkreterManagerA : public BaseManager {
    
    public:
    
    	KonkreterManagerA(){};
    	~KonkreterManagerA(){};
    
    	// Überschriebene Methoden
    	virtual void Update() {
    		// Überschreibe Methode Update
    	}
    };
    
    class KonkreterManagerB : public BaseManager {
    
    public:
    
    	KonkreterManagerB(){};
    	~KonkreterManagerB(){};
    
    	// Überschriebene Methoden
    	virtual void Render() {
    		// Überschreibe Methode Render
    	}
    };
    

    Oder bin ich da falsch an ?

    lg



  • Kommt auf den Anwendungsfall an.



  • Aber vom Prinzip her passt das so oder ?
    Wäre es klug die Methoden Init() usw. auszulagern hinweiß "Command Pattern" ? So könnte ich code anpassen ohne die Klasse öffnen zu müssen.



  • CodeBase schrieb:

    Ich habe mal wo gelesen das man immer auf ein Imterface Programmieren soll und nicht auf eine Implementierung.

    Mit Interface sind hier keine Klassen mit pure virtual Methoden gemeint. Das ist viel allgemeiner.

    Wenn du Software schreibst, die mit anderem Code zusammenarbeitet, dann sollst du dabei dich nur auf die Dinge verlassen, die dir die öffentliche Schnittstelle (Interface) der anderen Software zusichert. Du sollst nicht deinen Code so schreiben, dass er nur funktioniert, weil die Implementierung hinter der Schnittstelle bestimmte Eigenschaften hat.

    Damit wird dein Code robuster gegen Änderungen der Implementierung.



  • Soll heißen die IManager klasse kann ich mir sparen oder ? bzw. Sollte ich hier keine Pure Virtual Funktionen machen. Dachte nur ich baue es so auf damit ich die Implementierung von der Definition entkoppel aber in diesem Bsp. macht es vermutlich wenig sinn oder ?



  • MFK schrieb:

    CodeBase schrieb:

    Ich habe mal wo gelesen das man immer auf ein Imterface Programmieren soll und nicht auf eine Implementierung.

    Mit Interface sind hier keine Klassen mit pure virtual Methoden gemeint.

    "auf ein Imterface programmieren" ist eine Java/C#-Richtlinie. Da ist wegen Spracheinschränkungen (keine Templates, keine Mehrfachvererbung) wirklich auch ein Interface gemeint.

    In C++ wird das nicht so eng gesehen. Wer eine Bibliothek schreibt nimmt meist Templates. Als Anwendungsentwickler ist es oft egal, weil die meisten Klassen, die etwas miteinander zu tun haben, ein ähnliches Interface besitzen und es ausreicht, den Typ einer Variable anzupassen. Mit C++11 und auto geht das noch besser.

    Klassen mit virtuellen Funktionen kommen in C++ äussert selten vor*, wenn das einzige Ziel ist, gegen ein Interface programmieren zu können.

    * Zitiert bitte nicht nur die erste Hälfte des Satzes.

    CodeBase schrieb:

    Soll heißen die IManager klasse kann ich mir sparen oder ?

    Ja.



  • Hängt vom Anwendungsfall ab, du solltest erst ein mal erklären, was deine Managerklasse später können soll. Wenn es verschiedene konkrete Manager gibt, die sich in ihrem Verhalten unterscheiden, dann macht es Sinn. Einfach nur so jeder Klasse ein abstraktes Interface zu verpassen, nur um gegen das Interface programmieren zu können, macht keinen Sinn.



  • DocShoe schrieb:

    Hängt vom Anwendungsfall ab, du solltest erst ein mal erklären, was deine Managerklasse später können soll. Wenn es verschiedene konkrete Manager gibt, die sich in ihrem Verhalten unterscheiden, dann macht es Sinn. Einfach nur so jeder Klasse ein abstraktes Interface zu verpassen, nur um gegen das Interface programmieren zu können, macht keinen Sinn.

    Durchaus dachte ich daran das sich die Manager danach anders verhalten und mit Methoden erweitert werden oder eben nicht. Die Methoden wie Init(), Render() und Update() haben alle. Um sicher zu stellen, das diese auch vorhanden sind, dachte ich eben an eine Abstrakte Basisklasse, das dem Aufrufer garantiert, das diese Methoden Implementiert sind. Ob ein Manager dann um Methoden erweitert wird oder nicht, hängt dann von der Konkreten Implementierung ab. Diese wollte ich dann mit dem Strategy Pattern lösen.



  • CodeBase schrieb:

    Diese wollte ich dann mit dem Strategy Pattern lösen.

    Ich weise darauf hin, dass Strategy Patterns je nach Anwendungsfall durch std::function oder Policy-based Design gelöst werden, nicht durch Vererbung.

    Design Pattern sind für reine OOP-Sprachen mit begrenzten Mitteln. In denen schreibt man dann Code wie

    Executer executer = Executer.getExecuter();
    executer.execute();
    

    In C++ gilt das nicht unbedingt als guter Stil.



  • oblase schrieb:

    Design Pattern sind für reine OOP-Sprachen mit begrenzten Mitteln. In denen schreibt man dann Code wie

    Executer executer = Executer.getExecuter();
    executer.execute();
    

    In C++ gilt das nicht unbedingt als guter Stil.

    Wegen dem Prinzip der Verschwiegenheit ?

    Es geht mir darum. Ich habe mich, vor längerer Zeit, mit C++ beschäftigt und auch das ein oder andere gemacht (was sicher nicht dem OO Entsprach, da bin ich ehrlich). Beruflich bin ich dann in die Datenbankentwicklung eingestiegen. Meine Passion liegt aber immer noch bei C++ und ich beschäftige mich seit einiger Zeit wieder intensiv damit. Ein Freund gab mir das Buch "Entwurfsmuster von Kopf bis Fuß" (manche kennen das sicher). Das Problem daran ist das auf Java aufgebaut ist, aber die Pattern bleiben ja, vom Prinzip her, gleich. Ich möchte einfach einen sauberen Wiedereinstieg schaffen und Fragen gleich im vorraus aus dem Weg räumen. Das Prinzip des "Code soll für Erweiterungen offen aber für veränderungen geschlossen sein", gefällt mir und ich versuche das gerade zu verinnerlichen und auch anwenden zu können. Steinigt mich bitte nicht wenn ich dumme Fragen stelle oder ausdrücke verwende die vll. nicht 100% passen (wie Inrerface zb. 🙂 )

    lg



  • CodeBase schrieb:

    Ein Freund gab mir das Buch "Entwurfsmuster von Kopf bis Fuß" (manche kennen das sicher). Das Problem daran ist das auf Java aufgebaut ist, aber die Pattern bleiben ja, vom Prinzip her, gleich.

    Höhö, in Software Engineering hat der Dozent auf dieses Buch aufgebaut und es als Grundlage genutzt 😃

    Liest sich zwar gut, aber ist alles andere als wissenschaftlich... 😃
    Mit den Pizzas Hamburger Berliner und Münchner Art.



  • C++ bietet einfach mehr Mittel an. Die Entwurfsmuster von Java eignen sich solange auch für C++, wie man nicht bessere Lösungen nutzt. Mich regt an Java tierisch auf, dass man zig Interfaces und Klassen für die einfachsten Anwendungsfälle stricken muss (also bei einfachen Zusammenhängen, bei denen ein Design Pattern aber angebracht ist).

    Edit: Und mich regt an Dozenten auf, dass sie denken, die Designpattern-Welt von Java ist die von jeder Sprache, schön alle Sprachfeatures, die bessere Lösungen zulassen, vernachlässigend, weil ja sowieso "jeder Java nutzt" oder "OOP eben OOP ist". Aber das nur nebenbei.

    Wie man Strategy besser löst, hat oblase dann ja schon gesagt.

    Anderes Beispiel ist Listener/Observer-Pattern, das löst man in C++ brav mit slots/signals (boost und QT bieten das an).

    Grundsätzlich bietet C++ eine sehr starke statische Polymorphie an, was unter Java mit den schwachen Generics nur wenig ausgeprägt ist. Ich würde sagen, wenn zur Compilezeit Dinge feststehen können oder sollen, dann kann man sehr, sehr häufig (immer will ich mir nicht anmaßen zu sagen) auf viele Pattern Javas verzichten (oder diese abwandeln), weil man häufig keine Vererbung (auch von Interfaces) benötigt.

    Kannst ja weitere Designpatterns zur Diskussion stellen, wenn Du Dir unsicher bist. Ich finde die Diskussion sehr interessant und ein Design-Pattern-Buch für C++ habe ich auch noch nicht gesehen (wäre aber meiner Meinung nach durchaus Mal angebracht).



  • Naja das Design-Patterns Buch von den GoF ist in C++ und Smalltalk implementiert...

    Aber insofern hast du schon Recht, weil die 4 Kollegen nur die Prinzipien zeigen wollen und auch auf einfachste Features oder Must-Haves von C++ keinen Wert legen. Wenn ich mich recht erinnere, frickeln die an sehr vielen Stellen mit Pointern rum, anstatt Smart-Pointer oder Referenzen zu nutzen.
    Auf so Geschichten wie Policy-Based Design (was ja letztlich nichts anderes ist, als das Strategy Pattern) wird auch nur auf die Möglichkeit über Vererbung eingegangen.

    In Java legt man vor allem sehr viel Wert darauf alles zur Laufzeit zu ändern oder anzupassen (zu können). Das ist schön!
    Aber es verhindert Optimierungen, bremst dadurch die Performance und wird so oft nun auch nicht verwendet. Zumal es, wie ich finde, auch gar nicht mal so simpel ist mit Reflection und Spring und alles.

    Wie macht man das in C++?
    Letztlich durch neucompilieren oder durch DLLs (oder halt das entsprechende Pendant auf dem jeweiligen System).



  • Wow da ist ja eine echte Diskussion losgebrochen :).

    Also mir ist schon bewusst das, das Buch "Von Kopf bis Fuß" nicht unbedingt das beste Buch ist, aber es gibt einen einblick darauf wie Design Patterns funktionieren (ob alle bsp. jetzt 100% Passen sei mal dahin gestellt).

    Zum Thema Buch, was haltet ihr von diesem ?

    http://www.amazon.de/Modernes-Design-Programmierung-Entwurfsmuster-Professional/dp/3826613473/ref=reg_hu-rd_add_1_dp

    Prinzipiell finde ich Design Patterns eine schöne Sache. Besonders hatt es mir das Singelton Pattern angetan. Wobei ich hier auch schon viele meinungen über Statische Objekte gelesen habe.



  • Tja, das Buch ist gut, aber es ist schwer. Und so viel ist da nicht zu den herkömmlichen Patterns drin.

    Aber Alexandrescu ist einer, der weiss wovon er spricht, äh schreibt. (nicht so wie JW)

    Zum Singleton: Google einfach hier im Forum danach, du wünscht dir später du würdest diesen Begriff niemals gehört haben, so wird hier dafür oder dagegen geschrien 😃



  • Stimmt da geht es gut ab 😉 aber lassen wir die Diskussion nicht auf das Pattern rauslaufen das wird nichts ^^. Schreiben wir über die Factory Methode 😉 die ist interessant.

    Kennt jemand diese Seite

    http://sourcemaking.com/



  • Nein, sehr interessant, aber sieht eigentlich genauso aus wie der entsprechende Wikipedia Artikel über Patterns und Anti-Patterns...

    Factory Method Pattern = Template Method Pattern nur beim Erzeugen...



  • Kann mir das einer erklären ?

    http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern

    Irgendwie fühle ich mich gerade ein bisschen erschlagen und weiß gerade nicht was ich mir den jetzt genau anschauen soll und was nicht. Was gilt für C++ ? Was nicht ? Wo bekomme ich Pattern her die ich brauchen kann und wo werden die Beschrieben (vll. auch in Deutsch).



  • oblase schrieb:

    Design Pattern sind für reine OOP-Sprachen mit begrenzten Mitteln. In denen schreibt man dann Code wie

    Executer executer = Executer.getExecuter();
    executer.execute();
    

    In C++ gilt das nicht unbedingt als guter Stil.

    Die Aussage "Design Pattern sind für reine OOP-Sprachen mit begrenzten Mitteln" ist ja wohl ein noch viel schlimmerer Quatsch als das konkrete Beispiel das du bringst.



  • CodeBase schrieb:

    ich habe mal eine Frage. Ich habe mal wo gelesen das man immer auf ein Imterface Programmieren soll und nicht auf eine Implementierung.

    Jain. Gerade in C++ hast du mehrere Möglichkeiten dieser Art von Abstraktion. Man ist nicht auf Vererbung und virtuelle Funktionen beschränkt. Die Alternative heißt "generische Programmierung". Ich würde letzteres Vorziehen, weil es bzgl Performance kostenlos ist. Bei Gelegenheit kann man dann immer noch per Type-Erasure eine Art Laufzeitpolymorphie erhalten, beispielsweise Funktoren, die in einem std::function<>-Objekt drinstecken.

    Ich habe als Java-nach-C++ Umsteiger auch anfangs solche abstrakten Klassen geschrieben, weil es der einzige Abstraktionsmechanismus war, der mir vertraut war. Das ist allerdings 5 Jahre her. Und heute schreibe ich ganz anderen Code. new/delete/virtual sind Dinge, die ich höchst selten verwende. Ich habe gelernt, dass es viele Fälle gibt, in denen man so einen Polymorphismus zur Laufzeit gar nicht braucht. Es reicht ggf die Parameterisierung von Funktionen und Klassen zur Compilezeit (--> Templates). Und selbst das sollte man auch nicht übertreiben.


Log in to reply