2010-09-14 22 views
11

Niedawno dowiedziałem się o Law of Demeter.Czy łamie "Prawo Demeter"?

Podobnie jak wiele rzeczy, zdałem sobie sprawę, że to było coś, co już robiłem, ale nie miałem nazwy. Jest kilka miejsc, ale wydaje mi się, że go naruszam.

Na przykład ...

może mam obiektu Adres:

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

i obiekt klientów:

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, to jest fałszywy kod więc prawdopodobnie nie Muszę wskoczyć na mnie, aby użyć IoC, aby wyeliminować new Address() lub cokolwiek innego, ale jest to raczej przykład tego, co robię. Nie uwzględniłem interfejsów, ponieważ mam nadzieję, że są oczywiste.

chciałbym użyć go w moim kodu dla rzeczy jak int zip = customer.Address.Zip; i customer.Address.City = "Vancouver";

Jak rozumiem, mam naruszenie Prawo Demeter manipulując szczegóły Adres z Klientem.

Z drugiej strony wygląda na to, że framework również działa. W końcu nie adres. Długość.Czy to naruszenie? Czy powinienem dodawać metody do adresu, aby obsłużyć dostęp do właściwości łańcuchów? Prawdopodobnie nie. Więc po co zagracać Adres?

Nie mogę tak naprawdę dodawać metod do adresu, które odnoszą się tylko do klienta. Mam członków, pracowników, zależnych, dostawców, pracodawców, itp. Obiektów, które również mają adresy.

Czy jest lepszy sposób to obsłużyć? Jakie problemy napotykam, jeśli używam adresu tak jak teraz?

dla ludzi Java klasa Adres może wyglądać mniej więcej tak jak poniższy, czy to pomaga:

public class Address extends AddressInterface 
{ 
    private String m_city; 

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

Muszę przyznać, że customer.getAddress().setCity("Vancouver"); pierścienie więcej alarmów niż customer.Address.City = "Vancouver"; zrobił dla mnie. Może powinienem przełączyć się na Javę na jakiś czas.

+0

Co z mniejszością w C++? ( –

+0

Przepraszam Kornel, nie miałem na myśli braku szacunku, Post stał się dość długi, istnieje milion języków, które mogłem wykorzystać jako przykłady, jednak chłopaki z Javy wydają się kochać ich wzory i pomyślałem, że warto dodać fragment, jeśli to jest Jakiekolwiek spostrzeżenia na moje pytanie? – Justin

+1

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

Odpowiedz

11

Ten artykuł: http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx ma świetne wyjaśnienie problemów, które dyskutujesz.

Jak zauważa, nie jest to liczenie kropek, jest to problem z łączeniem. Obecnie twoje klasy Customer i Address są zbyt ściśle powiązane. Na początek, Customer nie powinien tworzyć nowych adresów, być może przekazać Address przy użyciu konstruktora.Co do tego, czy należy używać kropki, aby uzyskać dostęp do wielu części adresu, przeczytaj artykuł ...

Martin Fowler: „Wolałbym go nazwać Czasami Przydatne Sugestia Demeter”

+0

Uuuh, podoba mi się ten cytat: D – atamanroman

+0

Dziękujemy za opublikowanie tego jako odpowiedź. Cytat podsumowuje artykuł całkiem dobrze. – Justin

2

Naruszenia ustawy o Demeter są przypadki o zapachu kodu o nazwie Nieodpowiednia intymność. Aby usunąć ten zapach, możesz zreorganizować swój kod, ukrywając wewnętrzne adresy i metody wdrażania w kliencie, które delegują adres. W ten sposób szanujesz enkapsulację na adres wewnątrz Klienta.

przykład:

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

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

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

nadzieja pomaga.

+0

Ma również tę zaletę, jeśli twoja implementacja adresu zmienia się, po prostu musisz utrzymać jedną klasę – InsertNickHere

+0

W rzeczywistości, główny problem w Ta nieodpowiednia intymność nie dotyczy samej Klasy Klienta. Jest w klasach, które korzystają z klienta. Każda klasa, która uzyska dostęp do obiektów posiadanych przez klienta, wie zbyt wiele o Kliencie. Co więcej, wydaje się, że Klient i adres to rodzaj anemicznych klas, a jedynie kłaczki danych. – Stephan

1

Problem polega na tym, że adres jest obiektem ValueObject. Nigdy nie zmieniłbyś miasta bez zmiany suwaka.

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); 
    } 
}