Я нарушаю "Закон Деметры"?
Недавно я узнал о Закон Деметры.
Как и многие вещи, я понял, что это то, что я уже делал, но не имел названия. Есть несколько мест, хотя я, кажется, их нарушаю.
Например...
У меня может быть объект Address:
public class Address : IAddress
{
public string StreetAddress { get; set; }
public string City { get; set; }
public int Zip { get; set; }
}
и объект Customer:
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;
}
}
}
Хорошо, это поддельный код, поэтому вам, вероятно, не придется прыгать на меня, чтобы использовать IoC, чтобы исключить new Address()
или что-то еще, но это в значительной степени пример того, что я делаю. Я не включил интерфейсы, поскольку я надеюсь, что они очевидны.
Я бы использовал его в своем коде для таких вещей, как int zip = customer.Address.Zip;
и customer.Address.City = "Vancouver";
Как я понимаю, я нарушаю Закон Деметры, манипулируя деталями адреса от Клиента.
И снова, похоже, что и каркас. В конце концов, не будет ли адрес .City.Length быть нарушением? Должен ли я добавлять методы Address для обработки доступа к свойствам строки? Возможно нет. Итак, зачем загромождать адрес?
Я не могу просто добавить методы для адреса, которые относятся только к клиенту. У меня есть объекты Member, Employee, Dependent, Vendor, Employer и т.д., У которых также есть адреса.
Есть ли лучший способ справиться с этим? С какими проблемами я рискую, если буду использовать адрес так, как сейчас?
Для людей Java класс Address может выглядеть примерно следующим образом, если это помогает:
public class Address extends AddressInterface
{
private String m_city;
public String getCity() { return m_city; }
public void setCity(String city) { m_city = city; }
}
Я должен признать, что customer.getAddress().setCity("Vancouver");
вызывает больше тревог, чем customer.Address.City = "Vancouver";
сделал для меня. Возможно, мне нужно некоторое время переключиться на Java.
Ответы
Ответ 1
Эта статья: http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx имеет большое объяснение обсуждаемых вами проблем.
Поскольку он отмечает, что это не функция подсчета точек, это проблема связи. В настоящее время ваши классы Customer
и Address
слишком тесно связаны. Для начала Customer
не следует создавать новые адреса, возможно, передать Address
при использовании конструктора. Что касается использования нескольких точек для доступа к частям адреса, прочитайте статью...
Мартин Фаулер: "Я бы предпочел, чтобы это называлось иногда полезным предложением Деметры".
Ответ 2
Нарушения закона Деметры - это примеры кодового запаха с именем "Несовершенная близость". Чтобы удалить этот запах, вы можете реорганизовать свой код, спрятав внутренности адреса и методы реализации в Customer, которые делегируют адрес. Таким образом, вы уважаете инкапсуляцию по адресу внутри Клиента.
Пример:
public class Customer extends ICustomer{
private Address address;
....
public void setCity(String city){
address.setCity(city);
}
public String getCity(){
return address.getCity();
}
}
Надеюсь, что это поможет.
Ответ 3
Проблема здесь в том, что Address является ValueObject. Вы бы никогда не меняли город, не меняя почтовый индекс.
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 valid C#
public void setAddress(int zip){
address = Address.lookup(zip);
}
}