"Скажи, не спрашивай" над несколькими объектами домена

Вопрос

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

Пример - Генерация отчета

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

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

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

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 ответа

Решение

Отчет должен поддерживать способность создавать себя.

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

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

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

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

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

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

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

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

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

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 {
    ...
}

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

Другие вопросы по тегам