Design Patterns - manchmal auch nicht ganz so gutes Design?
-
Shade Of Mine schrieb:
moagnus schrieb:
Das Strategy-Objekt wird immer von einer anderen Klasse gefüttert, "leiht" sich also dessen Daten aus. Ich hatte nur so 'nen Satz wie "Keep data and related behavior in one place." im Kopf.
Ne, ist falsch.
Du rufst ja auch
std::sort auf um deinen vector zu sortieren.
algorithmen und daten muessen nicht zusammen sein...Recht habt ihr beide. Allgemeine Algorithmen arbeiten mit (idealerweise) beliebigen Daten. Spezielle Algorithmen nicht.
-
moagnus schrieb:
@hustbaer: Ich denke, Containerklassen kann man da ausnehmen, die sind ein Extremfall.
Hab ich was von Containerklassen geschrieben?
-
Ja, aber std::sort ist ja auch keine Memberfunktion. Ich weiß nicht, aber ich hab das Gefühl, dass bei Strategy zu viel Daten von außen eingegeben werden. Wenn ich mir dann vorstelle, dass ich mal meiner Strategy nen Zeiger auf ne Membervariable der Klasse, die die Strategy benutzt, übergebe und mittels des Zeigers dann irgendein Wert während des Algorithmuses (in einer Strategy-Methode) verändert wird, dann wird der Wert der Variable nicht mehr nur von seiner Klasse bestimmt, sondern von der Strategy-Methode.
Ist das ein berechtigter Einwand oder ist das Beispiel eher zu konstruiert und sollte ich mir hustbaers ersten Absatz bzgl. manchmal enge Kopplung ist okay zu Herzen nehmen?
-
moagnus schrieb:
Ich weiß nicht, aber ich hab das Gefühl, dass bei Strategy zu viel Daten von außen eingegeben werden.
Das ist halt ein Kompromiss. Dass jede Verantwortlichkeit bei dem Objekt liegt, das die dazugehörigen Daten enthält, ist nur ein Designprinzip von mehreren. Ein anderes wäre, dass man veränderliches Verhalten durch Polymorphie ausdrücken soll. Das beides geht nicht unter einen Hut zu bringen, also muss man sich überlegen, wo man was aufweicht.
-
@moagnus:
Du kannst dir ja aussuchen wie die "Strategy" mit dem "eigentlichen" Objekt kommuniziert. Ein Extrem wäre "friend", das andere Extrem wäre ne totale Entkopplung mittels SOAP Interface oder etwas in der Art. Nochmal eine andere Möglichkeit ist ein generisches Template-basiertes Interface, wie es oft in der Standard-Library anzutreffen ist (z.B. eben bei sort, partition etc.).Es gibt sicher Fälle wo es Sinn macht alles schön zu entkoppelt, und keinen "direkten" Zugriff auf die Eingeweide einer Klasse zu erlauben.
Es gibt aber auch Fälle, wo es gänzlich egal ist.
Wichtig ist doch hauptsächlich, dass ein Funktionsblock/Modul sauber von anderen Funktionsblöcken/Modulen getrennt ist. Das heisst aber nicht, dass ein Funktionsblock nicht aus 2, 3 oder auch mal 10 eng gekoppelten Klassen bestehen dürfte.
-
Das Strategie Pattern sagt doch überhaupt nichts darüber aus, ob und wie Daten vom Algorithmus manipuliert werden. Das ist eine Frage, wie Du den Algorithmus implementierst. Wenn Du Seiteneffekt vermeiden willst, dann manipulier halt nicht das übergebene Objekt sondern erzeuge ein neues und liefer das zurück.
Das Strategie Pattern besagt lediglich, dass man eine einheitliche Schnittstelle schafft, um Algorithmen polymorph austauschen zu können.
-
moagnus schrieb:
Ja, aber std::sort ist ja auch keine Memberfunktion.
Ich sehe den Unterschied nicht.
Die Strategy kann ja zB eine funktion sein.
class Context { private: boost::function<void(*)(int)> strategy; public: void setStrategy(boost::function<void(*)(int)> strategy) { this->strategy = strategy; } void execute(int data) const { strategy(data); } };
Wie du die Strategy Objekte mit Context und den Daten koppelst, ist dir selbst überlassen...
-
moagnus schrieb:
Ich denke, die Übergabe per Parameter ist der friend-Variante vorzuziehen, oder?
Kommt drauf an. Beispiel: Du hast ein Form/Webpage mit 30 Controls und die unterschiedlichen Bearbeitungsmodi dieses Forms sollen in ein Strategiemuster ausgelagert werden. Also ein Objekt setzt das Form im Nur-Lesen-Modus, eins in den Bearbeitungsmodus und eins in den Anfügemodus. Also ICH werde da bestimmt keine 30 Controlreferenzen übergeben.
-
witte schrieb:
moagnus schrieb:
Ich denke, die Übergabe per Parameter ist der friend-Variante vorzuziehen, oder?
Kommt drauf an. Beispiel: Du hast ein Form/Webpage mit 30 Controls und die unterschiedlichen Bearbeitungsmodi dieses Forms sollen in ein Strategiemuster ausgelagert werden. Also ein Objekt setzt das Form im Nur-Lesen-Modus, eins in den Bearbeitungsmodus und eins in den Anfügemodus. Also ICH werde da bestimmt keine 30 Controlreferenzen übergeben.
Du übergibts eine Referenz auf die Form... Die Form kennt ja die eigenen Controls. Oder übersehe ich da was? Schliesslich ist dem Strategy ja der Rest der Seite komplett egal...
-
Er wollte die Member (hier die Controls des Form) nicht public machen um die Kapselung nicht aufzubrechen, wenn ich das richtig verstanden habe. Also müssen doch entweder die Member übergeben werden oder die Strategieklassen sind friends und manipulieren den Client direkt.
-
Wobei C# ja leider kein "friend" kann... und "internal" ist halt etwas grob.
-
@Bashar: Ok, ich glaube "aufweichen" ist hier ein gutes Schlüsselwort.
@hustbaer: Ok, ich hatte da vielleicht eine zu idealistische Ansicht. Vollkommen voneinander entkoppelte Klassen sind wohl auch nicht immer möglich.
@byto: Ja, du hast recht. Ich schätze mal, mein Beispiel war zu überzogen. Ich versteh das Strategy-Pattern jetzt mal als hilfreichen Kompromiss.
@witte: Die Member public zu setzen, würde mir sowieso nicht einfallen. Die drei Möglichkeiten, die ich sehe - und die auch schon genannt wurden - sind:
1. Übergabe der notwendigen Parameter. Wenn sich das in Grenzen hält, scheint das mir die beste Variante zu sein.
2. Die Anfreundung der zwischen Klasse und Strategy-Klasse über "friend".
3. "Callback" vom Strategy-Objekt aus mittels Getter-Methoden. Das halte ich für die schlechteste Variante, da es das Interface der benutzenden Klasse aufbläht, und das in einer eigentlich unerwünschten Weise.Als Resümee versuch ich mal die engere Kopplung positiver zu sehn, sozusagen.
-
moagnus schrieb:
@hustbaer: Ok, ich hatte da vielleicht eine zu idealistische Ansicht. Vollkommen voneinander entkoppelte Klassen sind wohl auch nicht immer möglich.
Ich verstehe zwar nicht was daran idealistisch sein soll, aber OK, wenn du meinst