Шаблон Посетитель нарушает закон Деметры? - PullRequest
17 голосов
/ 09 октября 2011

Закон Деметры предполагает наименьшую связь между классами.

Это означает, что 90% всех получателей / установщиков, выставляющихся в классе, должны быть «удалены» и заменены «поведенческим» методом. В самом деле, это соответствует философии «говори, не спрашивай», потому что от клиента не ожидается, что он будет сам относиться к поведению с помощью плохих методов получения / установки. Это также уменьшает дублирующийся код, если то же действие используется в другом месте.

Это подразумевает огромные классы с множеством поведенческих методов и чрезмерным использованием делегирования, если мы хотим соблюдать принцип единой ответственности.

С другой стороны, определение шаблона посетителя:

Посетитель позволяет вам определять новую операцию без изменения классов элементов, с которыми он работает.

Итак, на первый взгляд кажется, что это противоречит ожиданиям закона Деметры:

  • Один (Посетитель) подразумевает структуру класса для обеспечения получения / установки, чтобы Посетитель мог изменять состояния объекта, не касаясь самого класса.

  • Другое (Деметра) предлагает заключать все поведенческие коды, непосредственно связанные с объектом, в один и тот же класс.

Итак, мой вопрос:

Когда мы можем считать, что класс закрыт для модификации и, таким образом, перестать добавлять поведенческие методы в него и поэтому предпочитаем добавлять их во вновь созданного посетителя с большим риском того, что клиент использует методы получения / установки вместо поведенческих методов, уже выставленных ранее в начальном классе?

1 Ответ

11 голосов
/ 09 октября 2011

Краткий ответ: нет .

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

Во-вторых, я никогда не видел описания шаблона посетителя, который подразумевает, что посещаемый объект должен иметь методы получения и установки, чтобы посетитель мог их изменять. Как и в случае любого другого объекта, идея состоит в том, чтобы использовать публичный API посещаемого объекта для выполнения любого расширения . Подразумевается, что иначе определенно идет вразрез с инкапсуляцией.

По другому вопросу меня немного смущает ваш последний абзац, поскольку я не знаю, говорите ли вы о принципе открытия / закрытия или о том, как создать функцию с использованием шаблона посетителя.

В одном примечании, я думаю, ключом является понимание того, что SOLID, Закон Деметры и все другие практики - это передовой опыт , а не передовой опыт («передовой опыт» является маркетинговый термин). Если вы возьмете любую из этих практик до крайности, они, вероятно, в конечном итоге повредят удобочитаемости или удобству обслуживания кода.

(кстати, хороший вопрос: D)


Преимущество принципа открытого / закрытого применяется в основном к коду, который будет использоваться другими людьми способами, которые мы не можем предвидеть (пример тому - фреймворки). Поэтому, если вы пишете фреймворк, вам нужно добавить точки расширения и использовать языковую функцию, чтобы предотвратить наследование класса (например, final в Java или запечатанный в C #) или просто позволив разработчику переопределить определенные методы. Идея состоит в том, чтобы не дать наивному пользователю переопределить важный бит объекта и заставить фреймворк неожиданным образом сломаться. Некоторые языки / фреймворки смеются над этим (например, Ruby / Rails) и поощряют пользователя открывать классы для добавления или изменения функций (с некоторым успехом).

Если вы пишете приложение (и у вас есть код), я бы посоветовал вам не уделять слишком много внимания принципу открытого / закрытого и сосредоточиться на применении закона Деметры (в разумной степени: D) .

...