Я прочитал почти все вопросы, помеченные как Закон Деметры. На мой конкретный вопрос нет ответа ни в одном из этих вопросов, хотя он очень похож. В основном мой вопрос заключается в том, что когда у вас есть объект со слоями композиции, но вам нужно извлекать значения свойств из различных объектов, как этого добиться и почему один подход лучше другого?
Допустим, у вас есть довольно стандартный объект, состоящий из других объектов, например:
public class Customer {
private String name;
private ContactInfo primaryAddress;
private ContactInfo workAddress;
private Interests hobbies;
//Etc...
public getPrimaryAddress() { return primaryAddress; }
public getWorkAddress() { return workAddress; }
public getHobbies() { return hobbies; }
//Etc...
}
private ContactInfo {
private String phoneNumber;
private String emailAddress;
//Etc...
public getPhoneNumber() { return phoneNumber; }
public getEmailAddress() { return emailAddress; }
//Etc...
}
private Interests {
private List listOfInterests;
}
Следующее будет нарушать Закон Деметры:
System.out.println("Phone: " + customer.getPrimaryAddress().getPhoneNumber());
System.out.println("Hobbies: " + customer.getHobbies().getListOfInterests().toString());
Я думаю, это также нарушит закон Деметры (пояснение?):
ContactInfo customerPrimaryAddress = customer.getPrimaryAddress();
System.out.println("Phone: " + customerPrimaryAddress.getPhoneNumber());
Предположительно, вы затем добавили бы в Customer метод getPrimaryPhoneNumber ():
public getPrimaryPhoneNumber() {
return primaryAddress.getPhoneNumber();
}
А затем просто позвоните: System.out.println ("Телефон:" + customer.getPrimaryPhoneNumber ());
Но если сделать это со временем, кажется, что на самом деле это создаст много проблем и будет работать вопреки замыслу Закона Деметры. Это превращает класс Customer в огромный набор геттеров и сеттеров, которые слишком много знают о своих внутренних классах. Например, кажется возможным, что однажды объект «Клиент» будет иметь разные адреса (а не только «основной» и «рабочий» адрес). Возможно, даже у класса Customer будет просто список (или другая коллекция) объектов ContactInfo, а не конкретные именованные объекты ContactInfo. Как в таком случае продолжать следовать Закону Деметры? Казалось бы, это противоречит цели абстракции. Например, это кажется разумным в том случае, когда у клиента есть список элементов ContactInfo:
Customer.getSomeParticularAddress(addressType).getPhoneNumber();
Кажется, что это может стать еще более безумным, когда вы думаете о некоторых людях, у которых есть мобильный и стационарный телефоны, а затем ContactInfo должен иметь набор телефонных номеров.
Customer.getSomeParticularAddress(addressType).getSomePhoneNumber(phoneType).getPhoneNumber();
В этом случае мы не только обращаемся к объектам внутри объектов внутри объектов, но также должны знать, каковы действительные типы addressType и phoneType. Я определенно вижу в этом проблему, но не знаю, как ее избежать. Особенно, когда любой класс, вызывающий это, вероятно, действительно знает, что они хотят вытащить номер «мобильного» телефона для «основного» адреса рассматриваемого клиента.
Как это можно было реорганизовать, чтобы оно соответствовало Закону Деметры и почему это было бы хорошо?