Gibt es hierfür ein Pattern?
-
brotbernd schrieb:
seldon schrieb:
Etwas in dieser Art?
class material_setter { // ...Gefährlich finde ich hier, dass die Berechnung irgendwann und ziemlich unerwartet stattfindet. z.B.
{ material_setter(mDay) ( 20, color1) ( 44, color2) (100, color3) (180, color4) ; //// HIER ist die Lebenszeit bereits vorbei. //// Er speichert das konstruierte Objekt ja nirgendwo int i = mDay.get(); } // huch, wird erst hier berechnet.Nö, siehe Kommentar
-
@seldon: Deinen Vorschlag finde ich interessant
,aber warum ist in deinem Bespiel
material_setter_tund
material_settergemischt (ich meine das _t ). War das ein versehen oder steckt da ein
Hintergrund drin den ich nicht verstehe ?Gruß Ulli
-
Autsch, ja sorry. Zu früh am morgen und zu flüchtig drauf geguckt. Es ist eigentlich das gleiche wie mein Beispiel, nur dass ich das Objekt beim ersten Aufruf in Foo erzeuge.
-
Artchi schrieb:
void setMaterial(Day &day, std::vector<std::pair<int, Color> &c) { for(int i=0; i<c.size(); i++) day.setMaterial(c[i].first, c[i].second); }Die Funktion sollte aber keine Memberfunktion von Day sein!
Vielleicht stehe ich gerade etwas auf dem Schlauch, aber warum keine Memberfunktion?
-
dooooomi schrieb:
Vielleicht stehe ich gerade etwas auf dem Schlauch, aber warum keine Memberfunktion?
Weil es eine reine Bequemlichkeits-Funktion ist und weder Zugriff auf die Innereien der Klasse liefert noch das eigentliche Interface der Klasse wirklich erweitert.
-
Ah, richtig, danke. Etwas gewöhnungsbedürftig, aber an dem Argument ist natürlich was dran.
-
Richtig, man muß eigentlich immer nur schauen, ob eine Funktion Zugriff auf protected oder private Members benötigt. Wenn nicht, ist die Funktion eine Static-Member-Funktion oder besser eine freie Funktion.
Komfort-Funktionen, die z.B. einfach nur mehrere public-Member-Funktionen "sammeln", auf jeden Fall als freie Funktion.
Browser b("http://test.de"); // ... b.clear(); b.loadCurrentURL();Kann man so komfortabler machen:
void reload(Browser &b) { b.clear(); b.loadCurrentURL(); } reload(b);
-
const_Ulli schrieb:
@seldon: Deinen Vorschlag finde ich interessant
,aber warum ist in deinem Bespiel
material_setter_tund
material_settergemischt (ich meine das _t ). War das ein versehen oder steckt da ein
Hintergrund drin den ich nicht verstehe ?Gruß Ulli
Ein Versehen. Ich hatte das erst als Template angelegt, weil aus dem ursprünglichen Posting die Typen von mDay und color[1-4] nicht hervorgingen, aber das wurde für ein Verdeutlichungsbeispiel zu unübersichtlich. Wenn man es als Template anlegt, ist eine Funktionsvorlage sinnvoll, um den Typen von mDay automatisch aufzulösen, also hatte ich da eine Trennung zwischen Funktionsvorlage material_setter und Typvorlage material_setter_t, und das _t habe ich versehentlich nicht überall entfernt, als ich mir der Einfachheit halber selbst Typnamen aus den Fingern gesogen habe.
-
Artchi schrieb:
Richtig, man muß eigentlich immer nur schauen, ob eine Funktion Zugriff auf protected oder private Members benötigt. Wenn nicht, ist die Funktion eine Static-Member-Funktion oder besser eine freie Funktion.
Tjoah, wenn das denn immer so klar wäre.
Was wenn eine kleine Änderung dazu führt, dass die ehemals "macht gar keinen Sinn als Member"-Funktion auf einmal 100x performanter als doch-Member-Funktion implementiert werden kann?
Klar, man kann die dann zu nem friend machen, aber das ist ja auch nicht schön.Ich will damit nicht grundsätzlich gegen freie Funktionen argumentieren. Nur... man sollte es sich schon gut überlegen. Und die Regel "wenns keine Memberfunktion sein muss, dann auch nicht machen" finde ich zu einfach.
-
Verstehe nicht so ganz was du mit der Performance meinst? Meinst du, wenn man direkt auf die privaten Member-Variablen zugreift?
Aber private Memebers darf man doch eh nicht nach draußen geben. Also würde die Regel nicht greifen. Ist wohl eher theoretischer Fall.
Gesetz den Fall, das man bemerkt, das man daraus eine Member-Funktion macht, weil es dadurch schneller wird. Was wäre dann das Problem die Komfortfunktion zu ändern?
void reload(Browser &b) { // OLD: // b.clear(); // b.loadCurrentURL(); // NEW: b.reload(); }Der Client-Code müsste also nicht mal zwangsweise geändert werden um die neue Member-Funktion zu nutzen, ohne die API-Kompatibilität zu brechen. Und der Compiler würde sicherlich die Komfortfunktion sowieso inline machen.
Alles wieder in Butter!

Klar, wenn man Einfluss auf Client-Code hat, könnte dieser natürlich direkt angepasst werden. Dann kann die freie Funktion gelöscht werden. Aber grundsätzlich sehe ich keinen Nachteil für spätere Erkenntnisse.
Gibt es eigentlich in C++11 ein Deprecated-Tag?

-
Pattern? schrieb:
Ich will nun bestimmte Dinge berechnen, nachdem das LETZTE Mal setMaterial() aufgerufen wurde.
Irgendwie fallen mir dazu Fluent-Interfaces ein (Die mir vor allen im C#-Umfeld untergekommen sind), die würden in etwa wie folgt aussehen (Handelt sich im wesentlichen um eine Factoryklasse):
FluentTypname fluent; Typname t = fluent .SetMaterial(20, color1) // <-- Methode gibt die Instanz selbst zurück... .SetMaterial( 44, color2) // ... so das weitere Aufrufe möglich sind. .SetMaterial(100, color3) .SetMaterial(180, color4) .Generate(); // <-- Diese Methode gibt das fertige Element vom Typ "Typname" zurück.Ich selbst nutzte dies in C++ bisher bei der Definition von Rechten und Standardrollen einer Benutzerverwaltung, die Schnittstelle war so zumindest gut lesbar, auch wenn ich noch Schachtelungsebenen hatte...
Bei mir sah das im wesentlichen dann so aus:
CDefiniereDatenBenutzerverwaltung fluent; fluent.DefiniereRecht(enum-Wert) // <-- Gibt eine eigene Fluentschnittstelle für Rechte zurück. .Bezeichnung("...") .Beschreibung("...") .Standardrolle(enum-Wert) .Standardrolle(enum-Wert) .ErfordertRecht(enum-Wert) .Erzeuge() // Rückkehr zum ursprünglichen fluent-objekt... // ... Definition weiterer Rechte, Standardrollen etc. ; return fluent.Erzeuge(); // <-- In meinen Fall aber keine Rückgabe sondern Generierung der DB-Einträge...Dadurch das nur die Erzeugungsmethode die Definition abschließen (und prüfen) konnte war hier eine Sicherstellung der Reihenfolge möglich.
-
@asc
das erzeuge() kannst du dir aber sparen, wie bereits vorher dargestellt wurde.In deinem Fall ginge das natürlich nicht mit dem destructor, da du den Rückgabewert brauchst, aber mir fallen spontan 2 alternativen ein:
//beides nur ganz grob skizziert //Möglichkeit1: über den Constructor //der Rückgabewert von fluent.SetMaterial(...); class FluentCreator{ //... } class Typname{ public: Typname(FluentCreator const& fluent){ m_member=fluent.erzeuge();//irgendwie so ;) } }; //Möglichkeit 2: conversion operator //der Rückgabewert von fluent.SetMaterial(...); class FluentCreator{ public: operator Typname(){ return erzeuge();//auch irgendwie so } };
-
otze schrieb:
@asc
das erzeuge() kannst du dir aber sparen, wie bereits vorher dargestellt wurde.Das erzeuge() ist aber gut für's Gewissen, weil dann eventuelle Exceptions nimmer aus nem Destruktor geflogen kommen

EDIT: OK, Blödsinn, vergiss es

Das war bezogen auf den ursprünglichen Code von seldon.
Deine Möglichkeit (1) finde ich im übrigen grässlich, weil sie Factory und Werkstück unnötigerweise extremst koppelt.
Deine Möglichkeit (2) finde ist vermutlich OK (obwohl ich Konvertierungsoperatoren so überhaupt nicht mag, aber das is bloss ne persönliche Abneigung)
-
Pattern? schrieb:
Hallo,
ich habe eine Klasse, der man beliebig viele Winkel/Farb Paare hinzufügen kann:
mDay->setMaterial(20, color1); mDay->setMaterial(44, color2); mDay->setMaterial(100, color3); mDay->setMaterial(180, color4);Ich will nun bestimmte Dinge berechnen, nachdem das LETZTE Mal setMaterial() aufgerufen wurde.
Ich könnte natürlich ein endMaterial() anbieten, aber das ist irgendwie unelegant. Gibts da vielleicht irgend ein Pattern, mit dem ich das machen könnte?Wie wäre es mit:
// Observer template<class T> class matobserver { matobserver(T &o) : m_o(o){ } ~matobserver(){ m_o.calc(); } private: T &m_o; }; // deine Klasse class Mat { void calc() { // calc here } void setMaterial(...) { // ... } }; int main() { Mat mat; { matobserver mo(mat); // INSERT MATERIALS HERE --> mat.setMaterial(/*...*/); mat.setMaterial(/*...*/); mat.setMaterial(/*...*/); mat.setMaterial(/*...*/); mat.setMaterial(/*...*/); mat.setMaterial(/*...*/); // <-- INSERT MATERIALS HERE } }ungetestet...
-
Artchi schrieb:
Gibt es eigentlich in C++11 ein Deprecated-Tag?

Nein, aber Attribute - und die darf der Compiler frei erfinden. Ich warte nur darauf dass Compiler ein deprecated-Attribut einführen

-
Artchi schrieb:
Richtig, man muß eigentlich immer nur schauen, ob eine Funktion Zugriff auf protected oder private Members benötigt. Wenn nicht, ist die Funktion eine Static-Member-Funktion oder besser eine freie Funktion.
Komfort-Funktionen, die z.B. einfach nur mehrere public-Member-Funktionen "sammeln", auf jeden Fall als freie Funktion.
Browser b("http://test.de"); // ... b.clear(); b.loadCurrentURL();Kann man so komfortabler machen:
void reload(Browser &b) { b.clear(); b.loadCurrentURL(); } reload(b);Was ist der Vorteil, wenn ich reload(b) anstatt b.reload() schreibe?
-
-
Und was ist jetzt besser, wenn man alle möglichen Methoden, die zu einer Klasse gehören, raus nimmt und in einen Namespace steckt oder ganz ohne Namespace, damit sie garkeiner mehr findet? Dann hat man einen "Monolith Namespace".
Im übrigen ist das für mich sowieso nicht das Problem bzw. die Lösung für Monoliths. Für micht sind die Problem-Klassen solche, die zuviel machen und nicht die, die viele Methoden haben. Z.B. ein GUIController der alle Elemente einer GUI enthält, sowas müsste man in mehrere sinnvolle Klassen aufteilen. Wenn man da nur alles in freie Funktionen steckt, wird das Design auch nicht besser, sondern nur die Methoden im GUIController weniger.
-
Hast du den Artikel überhaupt weiter als bis zur Überschrift gelesen?
Abschnitt 3 zum Beispiel? Dick mit Überschrift:
Membership Has Its Rewards -- and Its Costs
3. Which ones should be members, and which should not? Why?
Dann wärst du zum Beispiel über eine Fußnote auch an diesen Artikel gekommen:
-
asdfghjklbn schrieb:
Was ist der Vorteil, wenn ich reload(b) anstatt b.reload() schreibe?
Stell dir vor, du steckst die reload(Browser&)-Funktion in einer separaten Headerdatei.
Durch den Austausch der Header, kannst du ein anderes Verhalten für Reload erreichen, ohne die Browser-Klasse ändern oder davo erben zu müssen.
Ist ein Beispiel, was eine Trennung ermöglicht.