Gibt es hierfür ein Pattern?
-
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.
-
Artchi schrieb:
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.
Dann muss reload aber die einzige Funktion in dem Header sein, sonst musst du ja alles andere in dem Austauch-Header und dem Original-Header doppelt haben.
otze schrieb:
Hast du den Artikel überhaupt weiter als bis zur Überschrift gelesen?
Etwas weiter und ich fand ihn wahnsinnig anstrengend, bis er mal zu Punkt kommt. Ich wollte ihn überfliegen, aber das funktionierte nicht, dann kamen nur 100 Zeilen std::string und ich hatte keine Lust mehr. Mich interessiert auch nicht das man einen find-Algorithmen für andere Sachen verwenden kann, weil ich nicht sehe, wie ich einen "b.clear(); b.loadCurrentURL();" - Algorithmus wieder verwenden kann. Erklär doch mal mit eigenen Worten, welche Vorteile du konkret in einem reload(b) gegenüber b.reload() siehst.
-
asdfghjklbn schrieb:
Dann muss reload aber die einzige Funktion in dem Header sein, sonst musst du ja alles andere in dem Austauch-Header und dem Original-Header doppelt haben.
Richtig, so sieht es aus. Du mußt als User-Code nur einen anderen Header inkludieren. Die Klasse Browser mußt du nicht anfassen, besonders wichtig wenn sie nicht von dir ist.
asdfghjklbn schrieb:
Mich interessiert auch nicht das man einen find-Algorithmen für andere Sachen verwenden kann, weil ich nicht sehe, wie ich einen "b.clear(); b.loadCurrentURL();" - Algorithmus wieder verwenden kann. Erklär doch mal mit eigenen Worten, welche Vorteile du konkret in einem reload(b) gegenüber b.reload() siehst.
Der find-Algo ist nur ein Beispiel. Kann auch das Reload als Beispiel herhalten.
Es geht darum, das du als User einer Klasse nur die vorhandenen Member-Functions nutzen kannst. Du kannst die Klasse z.B. nur durch Vererbung verändern, obwohl du wahrscheinlich nur die Public Members nutzen willst.
Also, es gibt kein Reload. Was machst du?
Dabei willst du aber die Klasse verständlich halten. Das schaffst du nur, wenn du sie nicht mit Publics zumüllst.
Wahrscheinlich will jemand ein anderes Reload-Verhalten haben? Er will nicht nur den flüchtigen Cache löschen, sondern auch den auf der Platte?
Mann könnte also verschiedene Klassen ableiten oder die Klasse direkt erweitern und komplexer machen.Oder man lagert die Komfortfunktion in eine separate Funktion aus.
// browser_helper.hpp #include <browser.hpp> void reload(Browser &b) { b.clear(); b.loadCurrentURL(); }// browser_helper2.hpp #include <browser.hpp> void reload(Browser &)b; { b.clearBrowserDir(); b.clear(); b.loadCurrentURL(); }Ich brauche in meinem Code nur einen anderen Header inkludieren oder einfach nur die reload-Funktion selbst ändern. Aber die Browser-Klasse bleibt unangetastet! Ich kann mir dadurch z.B. das Rebuild des Browser-Projektes sparen. Vielleicht habe nicht mal die Sourcen zum Browser-Projekt? Und außerdem ist die Browser-Klasse weiterhin schlank geblieben: kein zweites Reload:
class Browser { public: void clear(); void clearBrowserDir(); void loadCurrentURL(); };// ohne freie Funktionen wird es komplex und der User // hat trotzdem keinen Vorteil class Browser { public: void clear(); void clearBrowserDir(); void loadCurrentURL(); void reload(); void clearBrowserDirAndReload(); };Ein weiterer Vorteil ist noch, das die freien Funktionen gehindert werden Schindluder zu treiben und somit Laufzeitfehler minimiert werden, da sie nur auf definierte Public-Members zugreifen dürfen. Um so mehr Public-Members du aber hast, um so mehr mußt du aufpassen, was du mit den Protected- und Private-Members anstellst. Gerade private und protected sollen unnötigen Zugriff verhindern.
-
OK, wenn die Klasse nicht von einem selber ist und man eine Komfortfunktion braucht, kann man die als freie Funktion machen.
Einen Browser würde ich aber auch anders machen. loadCurrentURL und reload sind irgendwie sowieso das gleiche. Ich würde glaub ich beide nicht haben, sondern einfach nur setURL(url). Wenn man die aktuelle url nochmal setzt, ist das reload. Das clear braucht man vorher nicht, weil der Browser vorher sowieso intern clear macht, wenn man eine url setzt, egal ob sie die alte oder eine neue ist. Wahrscheinlich würde ich clear nicht mal public machen. Braucht man das für irgendwas? Eigentlich braucht man nur eine Methode um einen neuen Tab zu öffnen. Ein clearCache würde ich anbieten, aber natürlich kein clearCacheAndDoSonstwas. Vielleicht entspricht mein Browser damit sogar noch dem Muster, dass meine Methoden alle auf private Sachen zugreifen, aber an sowas denke ich eigentlich nie. Wenn ich eine Klasse habe, die irgendeine komplexere Logik enthält, würde ich das in die Klasse machen, egal ob man das über public Methoden machen kann oder nicht, sondern einfach nur davon abhängig, ob die Logik zur Klasse gehört und aus Information Hiding Gründen da rein muss.
-
asdfghjklbn schrieb:
Einen Browser würde ich aber auch anders machen. loadCurrentURL und reload sind irgendwie sowieso das gleiche. Ich würde glaub ich beide nicht haben, sondern einfach nur setURL(url). Wenn man die aktuelle url nochmal setzt, ist das reload. Das clear braucht man vorher nicht, weil der Browser vorher sowieso intern clear macht, wenn man eine url setzt, egal ob sie die alte oder eine neue ist.
Der Browser wird sicherlich nicht den Cache von der aktuellen url clearen wollen bevor er die neue Seite lädt. Das ist in ca 95% der Fälle vom User nicht gewollt. Meistens drückt der User F5 und will einfach nur wissen ob sich auf der Seite was geändert hat. Dann möchte er nicht jedes Bild der Seite neu übertragen kriegen, sondern nur der Teil der neu ist(auf nem Handy wäre das sicher lustig...). Manchmal brauchst du aber ein expliziten neu laden aller Seitenteile (Shift+F5).
Damit hätten wir schon 2 Versionen:
reload();
und
reloadAndClearCache();Du könntest natürlich das erste reload durch setUrl(browser.currentUrl()) ersetzen, aber das ist einen ticken schwerer verständlich als browser.reload();
Andererseits möchtest du nicht unbedingt alle convenience-funktionen in der Klasse haben. Sie blähen sie nur unnötig auf - und sie sammeln sich an(wie wärs noch mit einer Version, die den html5-cache leert?)Das können auf die Dauer relativ viele Funktionen werden, die aber alle nur von ein paar wenigen Funktionen des Browsers abhängen. Kein Browser würde auf die Idee kommen, diese ganzen Funktionen neu zu implementieren, also kannst du die auch aus dem Interface raus werfen.
Für mich haben public interfaces einen weiteren Vorteil: ich kann relativ einfach meine Interfaces auf fremde Bibliotheken erweitern. wenn meine Klasse Foo ein bar(Foo) hat, und dann eine andere Bibliothek ein Foo2 anbietet das konzeptionell identisch mit Foo ist, dann kann ich dafür eine bar(Foo2) schreiben und habe eine wunderbare Generalisierung meines Interfaces erreicht. Mit Methoden könnte ich das eventuell nicht machen!
-
otze schrieb:
asdfghjklbn schrieb:
Einen Browser würde ich aber auch anders machen. loadCurrentURL und reload sind irgendwie sowieso das gleiche. Ich würde glaub ich beide nicht haben, sondern einfach nur setURL(url). Wenn man die aktuelle url nochmal setzt, ist das reload. Das clear braucht man vorher nicht, weil der Browser vorher sowieso intern clear macht, wenn man eine url setzt, egal ob sie die alte oder eine neue ist.
Der Browser wird sicherlich nicht den Cache von der aktuellen url clearen wollen bevor er die neue Seite lädt. Das ist in ca 95% der Fälle vom User nicht gewollt. Meistens drückt der User F5 und will einfach nur wissen ob sich auf der Seite was geändert hat. Dann möchte er nicht jedes Bild der Seite neu übertragen kriegen, sondern nur der Teil der neu ist(auf nem Handy wäre das sicher lustig...). Manchmal brauchst du aber ein expliziten neu laden aller Seitenteile (Shift+F5).
Damit hätten wir schon 2 Versionen:
reload();
und
reloadAndClearCache();OK, ich hatte mir unter clear nicht clearCurrentUrlCache vorgestellt, sondern einfach nur, dass die neue Seite nicht angehangen wird, darum meinte ich, dass der Browser das intern macht. Dann können wir ja ein clearUrlCache(url) hinzufügen. Wie das reload gemacht wird, ob mit clearUrlCache oder clearHtml5Cache(warum auch immer man das braucht) oder was auch immer ist nicht Sache des browsers und kommt nicht als reloadAnd... in den browser, hab ich schon gesagt bei clearCacheAndDoSonstwas. Man könnte höchstens als convenience Funktion zur Lesbarkeit ein reload(){setUrl(getUrl())} in den browser machen.