«Скажи, не спрашивай» над несколькими объектами домена - PullRequest
7 голосов
/ 09 марта 2012

Вопрос

Как придерживаться принципа «Говори, не спрашивай» при выполнении функции, включающей несколько объектов.

Пример - создание отчета

У меня есть следующие объекты (только для иллюстрации):

Автомобиль, Лошадь, Кролик

Между этими объектами нет никакой связи, но я хочу создать отчет на основе этих объектов:

createHtmlReport(Car car, Horse horse, Rabbit rabbit){
    Report report = new Report()

    report.setSomeField(car.getSerialNumber())
    report.setAnotherField(horse.getNumberOfLegs())
    // ...etc       
}

Проблема этого метода заключается в том, что он должен «извлекать» данные из каждого объекта,который нарушает правило «говори, не спрашивай».Я бы предпочел скрыть внутренности каждого объекта и сделать так, чтобы они генерировали для меня отчет:

car.createHtmlReport()   
horse.createHtmlReport()
rabbit.createHtmlReport()

... но тогда я получу 3 частичных отчета.Кроме того, я не думаю, что Кролик должен знать, как генерировать каждый отдельный отчет, который мне нужен (HTML, JMS, XML, JSON ....).

Наконец, при создании отчета я могу включить несколько элементов:

if (car.getWheels() == 4 || horse.getLegs() == 4)
    // do something

Ответы [ 4 ]

8 голосов
/ 09 марта 2012

В отчете должна быть возможность создавать себя.

В этом случае каждый объект IReportable должен реализовать void UpdateReport(Report aReport).

Когда вызывается Report.CreateReport(List<Reportable> aList), он повторяется.через List и каждый объект в своей собственной реализации UpdateReport вызывает:

aReport.AddCar(serialNumber)
aReport.AddHorse(horseName)

В конце CreateReport объект отчета должен выдавать свой собственный результат.

6 голосов
/ 10 марта 2012

Цель правила «Скажи, не спрашивай» состоит в том, чтобы помочь вам определить ситуации, когда ответственность, которая должна лежать на данном объекте, в конечном итоге будет реализована за его пределами (плохо).
Какие обязанности мы можем видеть в вашем случае? То, что я вижу:

1) умение форматировать отчет (в формате xml, ascii, html и т. Д.)
2) зная, что идет на какой отчет

Первый явно не относится к объекту домена (автомобиль, лошадь и т. Д.). Куда 2) идти? Можно предложить объект домена, но если в вашей системе несколько разных отчетов, вы в конечном итоге обремените свои объекты знаниями о различных деталях отчета, которые будут выглядеть и пахнуть плохо. Не говоря уже о том, что это нарушило бы принцип единственной ответственности: быть Кроликом - это одно, а знать, какие части информации о Кролике должны попадать в отчет X против отчета Y, - совсем другое. Таким образом, я бы разработал классы, которые инкапсулируют содержимое данных, которые поступают в отчет определенного типа (и, возможно, выполняют необходимые вычисления). Я бы не беспокоился о том, что они читают данные членов Кролика, Лошади или Автомобиля. Ответственность, которую реализует этот класс, заключается в «сборе данных для определенного типа отчета», который, как вы сознательно решили, должен лежать вне объекта домена.

3 голосов
/ 10 марта 2012

Это именно то, для чего Шаблон посетителя .

1 голос
/ 27 января 2013

Я не знаю точно, как называется этот шаблон (посетитель, строитель, ...):

public interface HorseView {
    void showNumberOfLegs(int number);
}

public interface CarView {
    void showNumberOfWheels(int number);
    void showSerialNumber(String serialNumber);
}

public class Horse {

    void show(HorseView view) {
        view.showNumberOfLegs(this.numberOfLegs);
    }

}

public class Car {

    void show(CarView view) {
        view.showNumberOfWheels(this.numberOfWheels);
        view.showSerialNumber(this.serialNumber);
    }

}

public class HtmlReport implements HorseView, CarView {

    public void showNumberOfLegs(int number) {
        ...
    }

    public void showNumberOfWheels(int number) {
        ...
    }

    public void showSerialNumber(String serialNumber) {
        ...
    }

}

public XmlModel implements HorseView, CarView {
    ...
}

public JsonModel implements HorseView, CarView {
    ...
}

Таким образом, вы можете иметь несколько представлений одного и того же доменного объекта, не нарушая принцип «Не говорите».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...