Tell don’t ask – Weg mit den Gettern [endlich-clean.net]
Im Zusammenhang mit dem Tell don’t ask Prinzip erläutere ich oft, dass man als Entwickler versuchen sollte, auf Getter zu verzichten. Danach schaue ich meist in ungläubige Gesichter
Heute bin ich in einem Video wieder mal darüber gestolpert (ab Minute 17:26 geht es um Mock Objekte, bei 20:02 um Smart Handlers). Ja, auch andere erzählen das. Deshalb muss es noch nicht richtig sein, aber ich halte den Ansatz nach wie vor für nützlich. Nicht im Sinne eines Dogmas wie etwa “Verwende keine Getter!”, sondern als ein nützliches Tool in meinem Werkzeugkasten.
Nehmen wir mal ein Beispiel, bei dem es auf Anhieb schwer fällt, sich die Klasse ohne Getter vorzustellen:
1: public class Kunde
2: {
3: public string Name { get; set; }
4: public string Vorname { get; set; }
5: public string Nummer { get; set; }
6: }
Aber wie wäre es damit:
1: public class Kunde
2: {
3: private string vorname;
4: private string name;
5: private string nummer;
6:
7: public void HandleDetails(KundeHandler handler) {
8: handler.Name(string.Format("{0} {1}", vorname, name));
9: handler.Nummer(nummer);
10: }
11: }
Wenn nun die Details eines solchen Kunde Objektes auf die Konsole geschrieben werden sollen, muss nur ein entsprechender Handler implementiert werden:
1: public class ConsoleWriter : KundeHandler
2: {
3: public void Name(string name) {
4: Console.WriteLine(name);
5: }
6:
7: public void Nummer(string nummer) {
8: Console.WriteLine(nummer);
9: }
10: }
Auch andere Aufgaben sind denkbar und leicht zu realisieren, wie z.B. Konvertierung/Mapping in ein ViewModel oder Data Tranfer Object.
Vorteile
Die Klassen halten das Single Responsibility Principle ein. Denn die Klasse übernimmt auf diese Weise nicht auch noch die Aufgabe der Darstellung, sondern delegiert diese an eine Handler Klasse.
Das Information Hiding Prinzip ist eingehalten. In obigem Beispiel ist es für den Handler völlig irrelevant, wie der Kundenname intern repräsentiert wird. Ob dazu zwei Felder, wie im Beispiel, verwendet werden oder nur eines ist nach außen nicht sichtbar. Durch den Wegfall der Getter sind die Beziehungen zwischen der Kunde Klasse und anderen reduziert.
Die Klasse behält ihre Automomie. Dies ist in der Regel eine Folge des Tell don’t ask Prinzip. Wenn Objekte nur Befehle entgegen nehmen, bleibt von außen keine Möglichkeit, auf unterschiedliche Zustände des Objektes zu reagieren. Der Zustand ist schlicht nicht sichtbar. Das führt dazu, dass die Logik in der Klasse landet, zu der sie gehört.
Nicht zuletzt können die einzelnen Klassen einfacher in Isolation getestet werden. Es wird nicht mehr ein Kunde Objekt in eine andere Klasse hineingereicht, sondern lediglich die benötigten skalaren Werte (oder auch komplexe Value Objects). Die Handler Objekte fungieren als Vermittler.
Fazit
Einfach mal ausprobieren!
September 3rd, 2009 at 14:27
endlich getter-los
Ich behaupte mal noch schlimmer als ein Getter ist ein Getter der bool(ean) zurückgibt.
September 3rd, 2009 at 15:16
Jep, ungefähr so:
if (!service.IsInitialized()) service.Initialize();
Grrrr…. Tell don’t ask! Wäre service.Initialize() idempontent, bräuchte es keinen Getter.
September 3rd, 2009 at 17:12
Hum…
Ich habe mir das Video ehrlich gesagt noch nicht angesehen, aber so ganz habe ich das “Problem” noch nicht verstanden. Könnte auch daran liegen, dass ich die “Lösung” noch nicht 100% nachvollziehen kann, aber vermutlich ist das Thema zu umfangreich und komplex um es mal eben zwischen “Tür und Angel” zu erfassen.
Hast du vielleicht Link-Tipps dazu, dann schaue ichs mir doch noch mal etwas genauer an.
Gruß, Gordon
September 5th, 2009 at 7:12
@Gordon
Links zu Tell don’t aks:
http://www.pragprog.com/articles/tell-dont-ask
http://c2.com/cgi/wiki?TellDontAsk
http://www.javangelist.de/space/Tell,+don‘t+ask
Grüße
Stefan
September 7th, 2009 at 8:21
Folgender Post nimmt sich auch dem Thema an:
http://jamesladdcode.com/?p=12
Der Autor nennt sein Vorgehen “East Bound”. Auch sehr interesant.
Bernd