В нашем приложении Delphi 2007 мы используем множество следующих конструкций
FdmBasic:=TdmBasicData(FindOwnerClass(AOwner,TdmBasicData));
FindOwnerClass перемещает иерархию Owner текущего компонента вверх, чтобы найти определенный класс (в примере TdmBasicData). Полученный объект сохраняется в переменной Field FdmBasic. Мы используем это прежде всего для передачи модулей данных.
Пример: при создании отчета результирующие данные сжимаются и сохраняются в поле Blob таблицы, доступ к которой осуществляется через модуль данных TdmReportBaseData. В отдельном модуле нашего приложения есть функциональные возможности для отображения данных из отчета в постраничной форме с использованием ReportBuilder. Основной код этого модуля (TdmRBReport) использует класс TRBTempdatabase для преобразования сжатых данных больших двоичных объектов в разные таблицы, которые можно использовать в конструкторе отчетов среды выполнения Reportbuilder. TdmRBReport имеет доступ к TdmReportBaseData для всех видов данных, связанных с отчетами (тип отчета, параметры расчета отчета и т. Д.). TRBTempDatabase создается в TdmRBReport, но должен иметь доступ к TdmReportBasedata. Так что теперь это делается с помощью конструкции выше:
constructor TRBTempDatabase.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FdmReportBaseData := TdmRBReport(FindOwnerClass(Owner, TdmRBReport)).dmReportBaseData;
end;{- .Create }
У меня такое ощущение, что это означает, что TRBTempDatabase много знает о своем владельце, и мне было интересно, если это какой-то запах кода или Anti-pattern.
Что вы думаете об этом? Это запах кода? Если так, что лучше?
источник
Ответы:
Этот вид выглядит как шаблон локатора сервиса, который был впервые описан Мартином Фаулером (который был идентифицирован как общий анти-паттерн).
Инжекция зависимостей на основе конструкции предпочтительнее, чем поиск сервисов, поскольку она обеспечивает наглядность требуемых параметров и упрощает модульное тестирование.
Также наиболее заметно, что это также нарушает закон Деметры
Лучший путь
По сути, лучший способ - удалить вызов локатора службы внутри класса и передать правильного владельца в качестве параметра внутри его конструктора. Даже если это означает, что у вас есть класс обслуживания, который выполняет поиск владельца, а затем передает его конструктору класса
источник
As a simple example, when one wants to walk a dog, it would be folly to command the dog's legs to walk directly; instead one commands the dog and lets it take care of its own legs.
Одна из трудностей, связанных с тем, что дочерние объекты слишком много знают о родительском объекте, заключается в том, что в итоге вы реализуете шаблоны, которые могут (и чаще всего это делают) становиться слишком тесно связанными, что создает головные боли, связанные с зависимостями, и часто впоследствии становится очень трудно безопасно модифицировать и поддерживать позже.
В зависимости от того, насколько глубоко связаны ваши два класса, это звучит немного похоже на описание Фаулером запахов кода зависти к функциям или несоответствующей интимности.
По-видимому, необходимо загрузить или прочитать класс с данными, и в этом случае вы можете использовать несколько альтернативных шаблонов, чтобы разорвать зависимость между ребенком и его цепочкой родителей, и кажется, что вам нужно делегировать задачу доступа ваш класс данных, а не делать класс доступа к данным ответственным за все сам.
источник