"Скажи, не спрашивай", когда один класс делает и сохраняет вычисления с данными из другого
Пожалуйста, скажите мне, если я применяю принцип Tell, не спрашивайте правильно в этом примере.
У меня есть два класса, CalculationResults
имеет функцию calculateMe()
, который использует Data
сделать некоторые расчеты. Важно, что он хранит результаты.
class Data {
private:
int dataForCalculations;
public:
void calculate(CalculationResults& calculationResults) {
calculationResults.calculateMe(dataForCalculations);
}
};
class CalculationResults {
private:
int calculatedData;
public:
void calculateMe(int dataForCalculations) {
calculatedData = someCalculations(dataForCalculations);
}
};
// somewhere else:
Data data;
CalculationResults calculationResults;
data.calculate(calculationResults);
Первая версия этого кода (до применения Tell, not ask) не использовалась Data::calculate
функция, но у нее есть getter
за dataForCalculations
так что где-то я звонил calculationResults.calculateMe(data.getDataForCalculations())
,
Новая версия лучше?
1 ответ
Новая версия лучше?
Это зависит от того, кого вы спрашиваете. Но чтобы быть уверенным, новая версия на 100% говорит, не спрашивайте. Это легко сказать, потому что ваши методы возвращают void.
Лично у меня была попытка просто следовать совету, не спрашивать принципа, и я отказался от него по нескольким причинам.
Например, принцип "не спрашивай" может привести к концептуальной путанице в объектных взаимодействиях. Возьмите ваш код для примера. Я бы не ожидал Data
объект, чтобы быть в состоянии рассчитать себя. Я бы ожидал Data
быть вкладом чего-то еще.
В качестве другого примера. Если бы я писал программу, которая смоделировала вызов кому-то, у меня могло бы быть Phone
, а также PhoneNumber
и Person
объект. Теперь, согласно сказанию, не спрашивайте, вы должны попросить объект с данными выполнить определенное действие. Итак, в этом случае PhoneNumber
может иметь метод dial(): phoneNumber.dial()
, Но имеет ли это смысл, концептуально? Действительно, Person
набирает PhoneNumber
в Phone
,
Итак, это моя первая проблема. Мне все труднее понять, и мне все труднее придумывать естественные взаимодействия между объектом с помощью "говори, не спрашивай", что замедляет меня.
Во-вторых, часто неясно, какой объект следует вызывать первым, когда двум объектам необходимо совместно использовать данные. Возьмите Book
и Pen
например. Вы говорите book.writeWith(pen)
или же pen.writeOn(book)
? Возможно, с этим примером можно поспорить, но часто вы обнаружите, что разница произвольна, и я ненавижу это.
В-третьих, если вы говорите, не спрашивайте, объект будет постепенно создавать все больше и больше обязанностей. Вы говорите объект, чтобы сохранить себя? Вы говорите это для отображения себя? Что делать, если у вас есть несколько технологий просмотра? Что если вам нужно отобразить ваш объект в разных форматах? Вы спрашиваете свой объект по электронной почте сам? Наличие объекта со многими обязанностями не обязательно плохо. Менее гибко изменить, но обеспечивает более легкую работу с API. Однако большинство людей предпочитают гибкость, и наличие объекта с небольшим количеством обязанностей является частью кода SOLID.
В-четвертых, в чем разница между тем, чтобы ваш объект передавался частным образом другим объектам с помощью команды Tell, не спрашивать (когда вам нужно обмениваться данными), и иметь геттер? Не очень, если вы спросите меня.
Я знаю, что это основано на мнениях, но я предпочитаю вашу первую версию лучше, потому что она проще и понятнее. Тем не менее, я бы написал это так:
calculationResults.calculate(data);
В любом случае, только мои 2 цента.