Это дизайнерское решение, которое, кажется, приходит довольно много: как передать контекст через метод, который ему не нужен, в метод, который это делает. Есть ли правильный ответ или это зависит от контекста.
Пример кода, который требует решения
// needs the dependency
function baz(session) {
session('baz');
}
// doesn't care about the dependency
function bar() {
baz();
}
// needs the dependency
function foo(session) {
session('foo')
bar();
}
// creates the dependency
function start() {
let session = new Session();
foo(session);
}
Возможные решения
- ThreadLocal
- Глобальный
- контекстный объект
- передать зависимость через
- карри баз и передать его в бар с зависимостью, установленной в качестве первого аргумента
- внедрение зависимости
Примеры того, где это подходит
Обработка HTTP-запроса
Часто используются объекты контекста в форме атрибутов запроса: см. Expressjs, Java Servlets или .net.
логирование
Для регистрации Java люди часто используют глобалы / синглтоны. Посмотрите типичные шаблоны log4j / commons logging / java logging.
операции
Локальные потоки часто используются для хранения транзакции или сеанса, связанных с цепочкой вызовов методов, чтобы избежать необходимости передавать их в качестве параметров всем методам, которые в них не нуждаются.
design-patterns
Джейми МакКриндл
источник
источник
Ответы:
Единственный справедливый ответ - это то, что это зависит от идиом вашей программной парадигмы. Если вы используете ОО, почти наверняка неправильно передавать зависимость от метода к методу. Это кодовый запах в ОО. Фактически это одна из проблем, которую решает ОО - объект исправляет контекст. Таким образом, в ОО один правильный (всегда есть другие способы) подход заключается в доставке зависимости через конструктор или свойство. Комментатор упоминает «Внедрение зависимостей», и это совершенно законно, но это не является строго необходимым. Просто предоставьте зависимость, чтобы она была доступна как член
foo
иbaz
.Вы упоминаете карри, поэтому я предполагаю, что о функциональном программировании не может быть и речи. В этом случае философским эквивалентом контекста объекта является замыкание. Любой подход, который, опять же, исправляет зависимость, чтобы она была доступна для зависимых, работает просто отлично. Карри - один из таких подходов (и он заставляет вас звучать умно). Просто помните, что есть и другие способы преодоления зависимости. Некоторые из них элегантны, а некоторые ужасны.
Не забывайте об Аспектно-ориентированном программировании . В последние несколько лет он, похоже, потерял самообладание, но его главная цель - решить именно ту проблему, которую вы описываете. Фактически, классический пример Aspect - это регистрация. В AOP зависимость добавляется автоматически после написания другого кода. Люди АОП называют это " ткачеством ". Общие аспекты вплетены в код в соответствующих местах. Это делает ваш код более легким для размышления и чертовски крутым, но также добавляет новый груз для тестирования. Вам понадобится способ определить, являются ли ваши последние артефакты здоровыми. У AOP есть ответы и на это, так что не пугайтесь.
источник
Если
bar
зависит от тогоbaz
, что в свою очередь требуетdependency
, тоbar
требуетdependency
тоже, чтобы правильно использоватьbaz
. Следовательно, правильными подходами было бы либо передать зависимость в качестве параметраbar
, либо карриbaz
и передать ееbar
.Первый подход проще реализовать и прочитать, но создает связь между
bar
иbaz
. Второй подход устраняет эту связь, но может привести к менее четкому коду. То, какой подход является наилучшим, вероятно, будет зависеть от сложности и поведения обеих функций. Например, еслиbaz
илиdependency
имеют побочные эффекты, простота тестирования, вероятно, будет большим драйвером, в котором выбрано решение.Я бы посоветовал всем другим вариантам, которые вы предлагаете, иметь «хакерскую» природу и, вероятно, привести к проблемам как с тестированием, так и с трудностями выявления ошибок.
источник
dependency
через параметры - это внедрение зависимостей?Философски говоря
Я согласен с беспокойством Дэвида Арно .
Я читаю ОП как поиск решений для реализации. Тем не менее, ответ - изменить дизайн . «Узоры»? ОО дизайн, можно сказать, все о контексте. Это огромный чистый лист бумаги, наполненный возможностями.
Работа с существующим кодом - это другой, ну, контекст.
Сейчас я работаю над той же проблемой. Ну, я исправляю сотни строк кода copy-n-paste, которые были сделаны только для того, чтобы можно было ввести значение.
Модульный код
Я выбросил 600 строк повторяющегося кода, а затем рефакторинг, поэтому вместо «А звонки Б звонки С звонки D ...» у меня есть «Звонок А, возврат, Звонок Б, возврат, Звонок С ...». Теперь нам нужно только ввести значение в один из этих методов, скажем, метод E.
Добавьте параметр по умолчанию в конструктор. Существующие абоненты не меняются - здесь указывается слово «по желанию». Если аргумент не передан, используется значение по умолчанию. Затем изменяется только 1 строка, чтобы передать переменную в измененную модульную структуру; и небольшое изменение в методе Е, чтобы использовать его.
Затворы
Поток программистов - "Почему программа использует замыкание?"
По сути, вы вводите значения в метод, который возвращает метод, настроенный со значениями. Этот настроенный метод впоследствии выполняется.
Этот метод позволит вам изменить существующий метод без изменения его сигнатуры.
источник