2010-09-14 23 views
11

Recientemente me di cuenta del Law of Demeter.¿Estoy rompiendo la "Ley de Demeter"?

Como muchas cosas, me di cuenta de que era algo que ya estaba haciendo pero que no tenía nombre. Sin embargo, hay algunos lugares en los que parezco violarlo.

Por ejemplo ...

que podría tener un objeto Dirección:

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

y un objeto Cliente:

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, esto es falso código por lo que probablemente no lo hace Tengo que saltar sobre mí para usar IoC para eliminar el new Address() o cualquier cosa, pero es más o menos un ejemplo de lo que estoy haciendo. No incluí las interfaces, ya que espero que sean obvias.

Me luego usarlo en mi código para cosas como int zip = customer.Address.Zip; y customer.Address.City = "Vancouver";

Como yo lo entiendo, estoy violando la Ley de Demeter mediante la manipulación de datos de Dirección del Cliente.

Por otra parte, parece que el marco también lo es. Después de todo, no abordaría.City.Length ser una violación? ¿Debo agregar métodos a la dirección para manejar el acceso a las propiedades de la cadena? Probablemente no. Entonces, ¿por qué desordenar la dirección?

Realmente no puedo agregar métodos a la dirección que se relacionen solo con el cliente. Tengo objetos de Miembro, Empleado, Dependiente, Vendedor, Empleador, etc. que también tienen direcciones.

¿Hay una mejor manera de manejar esto? ¿A qué tipo de problemas me arriesgo si utilizo Address tal como soy ahora?

Para la gente de Java, la clase de dirección podría ser algo más parecido a la siguiente si ayuda:

public class Address extends AddressInterface 
{ 
    private String m_city; 

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

he de reconocer que customer.getAddress().setCity("Vancouver"); anillos más alarmas que customer.Address.City = "Vancouver"; hicieron por mí. Tal vez debería cambiar a Java por un tiempo.

+0

¿Qué pasa con C++ folks minority? ;. ( –

+0

Lo sentimos Kornel que significaba ninguna falta de respeto El puesto estaba poniendo muy larga Hay un millón de lenguas que podría haber utilizadas como ejemplos los tipos de Java parece que aman a sus patrones y aunque pensé que valía la pena añadir un fragmento de si... ayudaría. ¿Alguna idea de mi pregunta? – Justin

+1

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

Respuesta

11

Este artículo: http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx tiene una gran explicación de los problemas que está discutiendo.

Como señala que no es un ejercicio de contar puntos, se trata de un problema de acoplamiento. Actualmente sus clases Customer y Address están muy juntas. Para empezar, Customer no debería estar haciendo nuevas direcciones, tal vez pase un Address usando un constructor.En cuanto a si debe usar múltiples puntos para acceder a partes de la dirección, lea el artículo ...

Martin Fowler: "Preferiría que se lo llamara Ocasionalmente Sugerencia Útil de Demeter".

+0

Uuuh, me gusta esa cita: D – atamanroman

+0

Gracias por publicar esto como una respuesta. La cita resume bastante bien el artículo. – Justin

2

Violaciones de la Ley de Demeter son ejemplos de un olor a código llamado Inapropiada Intimidad. Para eliminar este olor, puede refactorizar su código ocultando las partes internas de la dirección y los métodos de implementación en el Cliente que delegue en la dirección. De esta manera, respeta la encapsulación en la dirección dentro del Cliente.

Ejemplo:

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

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

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

Espero que esto ayude.

+0

También tiene el beneficio si la implementación de su dirección cambia, solo tiene que mantener una clase. – InsertNickHere

+0

En realidad, el principal problema w con esta intimidad inapropiada no está en la clase del Cliente en sí. Está en las clases que usan al Cliente. Cualquier clase que tenga acceso a objetos en poder del cliente sabe demasiado sobre el Cliente. Además, parece que el Cliente y la dirección son un tipo de clases anémicas, simplemente agrupaciones de datos. – Stephan

1

El problema aquí es que Address es un ValueObject. Nunca cambiarías la ciudad sin cambiar el código postal.

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