2010-09-14 4 views
11

Ich wurde erst kürzlich auf die Law of Demeter aufmerksam.Bricht ich das "Demeter-Gesetz"?

Wie viele Dinge, erkannte ich, dass es etwas war, das ich schon tat, aber keinen Namen hatte. Es gibt jedoch ein paar Orte, an denen ich es zu verletzen scheint.

Zum Beispiel ...

ich ein Address-Objekt haben könnte:

public class Address : IAddress 
{ 
    public string StreetAddress { get; set; } 
    public string City { get; set; } 
    public int Zip { get; set; } 
} 

und ein Customer-Objekt:

public class Customer : ICustomer 
{ 
    private IAddress address; 

    Customer() 
    { 
     Address = null; 
    } 
    public string Name { get; set; } 
    public IAddress 
    { 
     get 
     { 
     if (address == null) 
     { 
      address = new Address(); 
     } 
     return address; 
     } 
     set 
     { 
     address = value; 
     } 
    } 
} 

Ok, das ist fake Code, so dass Sie wahrscheinlich nicht tun muss auf mich springen, um IoC zu verwenden, um die new Address() oder irgendetwas zu beseitigen, aber es ist so ziemlich ein Beispiel von dem, was ich tue. Ich habe die Schnittstellen nicht einbezogen, da ich hoffe, dass sie offensichtlich sind.

dann würde ich in meinem Code für Dinge verwendet es wie int zip = customer.Address.Zip; und customer.Address.City = "Vancouver";

Wie ich es verstehe, ich bin Verstoß gegen das Gesetz von Demeter durch Details von Namen und Anschrift des Kunden zu manipulieren.

Dann scheint es, als ob das Framework auch so funktioniert. Schließlich würde nicht Adresse.Stadt.Länge eine Verletzung sein? Sollte ich Methoden hinzufügen, um den Zugriff auf String-Eigenschaften zu behandeln? Wahrscheinlich nicht. Also, warum durcheinander Address?

Ich kann nicht wirklich nur Methoden hinzufügen, die sich nur auf Kunden beziehen. Ich habe Mitglieder, Angestellte, Abhängige, Verkäufer, Arbeitgeber usw. Objekte, die alle auch Adressen haben.

Gibt es einen besseren Weg, damit umzugehen? Welche Art von Problemen riskiere ich, wenn ich Address so nutze, wie ich jetzt bin?

Für die Java-Leute könnte die Klasse Address etwas aussehen wie die folgende, wenn es hilft:

public class Address extends AddressInterface 
{ 
    private String m_city; 

    public String getCity() { return m_city; } 
    public void setCity(String city) { m_city = city; } 
} 

Ich muss zugeben, dass customer.getAddress().setCity("Vancouver"); Ringe mehr Alarme als customer.Address.City = "Vancouver"; für mich getan hat. Vielleicht sollte ich für eine Weile nach Java wechseln.

+0

Was ist mit der C++ - Minderheit? ; ( –

+0

Sorry Kornel. Ich meinte keine Respektlosigkeit. Der Beitrag wurde ziemlich lang. Es gibt eine Million Sprachen, die ich hätte als Beispiele verwenden können. Die Java-Typen scheinen ihre Muster zu lieben und ich dachte, es wäre wert, ein Snippet hinzuzufügen würde helfen, irgendwelche Einblicke in meine Frage? – Justin

+1

Siehe http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx –

Antwort

11

Dieser Artikel: http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx hat eine großartige Erklärung der Probleme, die Sie diskutieren.

Da er merkt, es ist kein Punkt zählen Übung, es ist eine Kopplungsproblem. Derzeit sind Ihre Customer und Address Klassen zu eng gekoppelt. Für den Anfang, Customer sollte nicht neue Adressen machen, vielleicht übergeben Sie einen Address mit einem Konstruktor.Um herauszufinden, ob Sie mehrere Punkte verwenden sollten, um auf Teile der Adresse zuzugreifen, lesen Sie den Artikel ...

Martin Fowler: "Ich würde es lieber den gelegentlich nützlichen Vorschlag von Demeter nennen."

+0

Uuuh, ich mag das Zitat: D – atamanroman

+0

Vielen Dank für das Posten als Antwort. Das Zitat fasst den Artikel ziemlich gut zusammen. – Justin

2

Verstöße gegen das Gesetz von Demeter sind Instanzen eines Code-Geruchs namens Inadäquate Intimität. Um diesen Geruch zu entfernen, können Sie Ihren Code umstrukturieren, indem Sie die Interna der Adresse und die Implementierungsmethoden in Customer ausblenden, die an die Adresse delegieren. Auf diese Weise respektieren Sie die Kapselung der Adresse innerhalb des Kunden.

Beispiel:

public class Customer extends ICustomer{ 
    private Address address; 
    .... 

    public void setCity(String city){ 
     address.setCity(city); 
    } 

    public String getCity(){ 
     return address.getCity(); 
    } 
} 

Hoffnung, das hilft.

+0

Es hat auch den Vorteil, wenn sich Ihre Adressimplementierung ändert, Sie müssen nur eine Klasse pflegen – InsertNickHere

+0

Eigentlich das Hauptproblem w ie diese unangemessene Intimität liegt nicht in der Kundenklasse selbst. In den Klassen wird der Kunde verwendet. Jede Klasse, die Zugriff auf Objekte erhält, die von Kunden gehalten werden, weiß zu viel über den Kunden. Außerdem scheinen Kunde und Adresse eine Art von anämischen Klassen zu sein, lediglich Datenklumpen. – Stephan

1

Das Problem hier ist, dass Adresse ein ValueObject ist. Du würdest niemals die Stadt wechseln, ohne den Reißverschluss zu ändern.

public class Customer extends ICustomer{ 
    private Address address; 
    .... 

    public void setAddress(String street, String city, int zip){ 
     address = Address.new(street, city, zip); 
    } 
    // or even better but i'm not sure if it's valid C# 
    public void setAddress(int zip){ 
     address = Address.lookup(zip); 
    } 
} 
Verwandte Themen