Предположим, у нас есть программный модуль A, который реализует функцию F. Другой модуль B реализует ту же функцию, что и F '.
Есть несколько способов избавиться от дубликата кода:
- Пусть A использует F 'из B.
- Пусть B использует F из A.
- Поместите F в его собственный модуль C и позвольте A и B использовать его.
Все эти параметры создают дополнительные зависимости между модулями. Они применяют принцип СУХОЙ за счет увеличения сцепления.
Насколько я вижу, при применении СУХОГО сцепление всегда увеличивается или в аренду перемещается на более высокий уровень. Кажется, существует конфликт между двумя из самых основных принципов разработки программного обеспечения.
(На самом деле я не нахожу удивительным, что есть такие конфликты. Вероятно, это и делает создание хорошего программного обеспечения таким сложным. Я нахожу удивительным, что эти конфликты обычно не рассматриваются во вводных текстах.)
Изменить (для пояснения): я предполагаю, что равенство F и F 'не просто совпадение. Если F нужно будет изменить, F ', вероятно, придется изменить таким же образом.
источник
Ответы:
Почему да, они делают. Но они уменьшают связь между линиями. То, что вы получаете, это сила, чтобы изменить соединение. Муфта бывает разных форм. Извлечение кода увеличивает косвенность и абстракцию. Увеличение может быть хорошим или плохим. Номер один, который решает, что вы получите, это имя, которое вы используете для него. Если, глядя на имя, я удивляюсь, когда заглядываю внутрь, значит, ты никому не сделал одолжений.
Кроме того, не следуйте за СУХОЙ в вакууме. Если вы убьете дублирование, вы берете на себя ответственность за предсказание того, что эти два использования этого кода изменятся вместе. Если они могут измениться независимо, вы вызвали путаницу и дополнительную работу ради небольшой выгоды. Но действительно хорошее имя может сделать это более приемлемым. Если все, что вы можете думать, это плохое имя, тогда, пожалуйста, просто прекратите сейчас.
Связь всегда будет существовать, если ваша система не будет настолько изолирована, что никто никогда не узнает, работает ли она. Так что рефакторинг связи - это игра выбора вашего яда. Следование DRY может окупиться, сводя к минимуму создаваемую связь, повторяя одно и то же дизайнерское решение во многих местах, пока его очень трудно изменить. Но СУХОЙ может сделать невозможным понимание вашего кода. Лучший способ спасти эту ситуацию - найти действительно хорошее имя. Если вы не можете придумать хорошее имя, я надеюсь, что вы умеете избегать бессмысленных имен
источник
Есть способы нарушить явные зависимости. Популярным является внедрение зависимостей во время выполнения. Таким образом, вы получите СУХОЙ, снимите сцепление за счет статической безопасности. Это настолько популярно в наши дни, что люди даже не понимают, что это компромисс. Например, контейнеры приложений обычно обеспечивают управление зависимостями, чрезвычайно усложняя программное обеспечение, скрывая сложность. Даже простой ввод в конструктор не гарантирует некоторые контракты из-за отсутствия системы типов.
Ответить на заголовок - да, это возможно, но будьте готовы к последствиям времени выполнения рассылки.
Таким образом, единственный тип зависимостей, который у вас будет, - это D, зависящий от каждого другого модуля.
Или зарегистрируйте C в контейнере приложения со встроенным внедрением зависимостей и наслаждайтесь удачным автоматическим подключением медленно растущих циклов загрузки классов и тупиковых ситуаций.
источник
Я не уверен, что ответ без дальнейшего контекста имеет смысл.
Есть ли
A
уже зависитB
или наоборот? - в этом случае у нас может быть очевидный выбор дома дляF
.Есть
A
иB
уже есть какие-то общие зависимости, которые могут быть хорошим домом дляF
?Насколько большой / сложный
F
? От чего ещеF
зависит?Модули
A
иB
используются в одном проекте?Будет ли
A
и вB
конечном итоге обмена некоторые общие в любом случае зависимость?Какой язык / модульная система используется: Насколько болезненен новый модуль с точки зрения программиста и с точки зрения снижения производительности? Например, если вы пишете на C / C ++ с модульной системой COM, которая причиняет боль исходному коду, требует альтернативных инструментов, влияет на отладку и влияет на производительность (для межмодульных вызовов), я мог бы Возьми серьезную паузу.
С другой стороны, если вы говорите о Java или C # DLL, которые довольно легко объединяются в одной среде выполнения, это другой вопрос.
Функция является абстракцией и поддерживает DRY.
Однако хорошие абстракции должны быть полными - неполные абстракции вполне могут привести к тому, что потребляющий клиент (программист) восполнит дефицит, используя знания базовой реализации: это приводит к более тесной связи, чем если бы абстракция была предложена вместо более полной.
Итак, я бы поспорил, чтобы попытаться создать лучшую абстракцию
A
иB
зависеть от нее, чем просто перенести одну единственную функцию в новый модульC
.Я бы искал набор функций, чтобы раскрыться в новой абстракции, то есть я мог бы подождать, пока кодовая база продвинется дальше, чтобы определить более полный / более полный рефакторинг абстракции для выполнения, а не один на основе на один код функции расскажи.
источник
Does A already depend on B or vice versa? — in which case we might have an obvious choice of home for F.
Это предполагает, что A всегда будет полагаться на B (или наоборот), что является очень опасным допущением. Тот факт, что OP видит F как неотъемлемую часть A (или B), предполагает, что F существует, не будучи присущим ни одной из библиотек. Если F принадлежит одной библиотеке (например, метод расширения DbContext (F) и библиотека-оболочка Entity Framework (A или B)), то вопрос OP будет спорным.Здесь ответы, которые сосредоточены на всех способах, которыми вы можете «минимизировать» эту проблему, оказывают вам медвежью услугу. А «решения», просто предлагающие разные способы создания связи, на самом деле вовсе не являются решениями.
Правда в том, что вы не понимаете самой проблемы, которую вы создали. Проблема с вашим примером не имеет ничего общего с DRY, скорее (в более широком смысле) с дизайном приложения.
Спросите себя, почему модули A и B разделены, если они оба зависят от одной и той же функции F? Конечно, у вас будут проблемы с управлением зависимостями / абстракцией / связыванием / you-name-it, если вы сделаете плохой дизайн.
Правильное моделирование приложения выполняется в соответствии с поведением. Таким образом, части A и B, которые зависят от F, должны быть извлечены в их собственный, независимый модуль. Если это невозможно, то A и B необходимо объединить. В любом случае A и B больше не являются полезными для системы и должны прекратить свое существование.
СУХОЙ - принцип, который может использоваться, чтобы выставить плохой дизайн, а не вызвать его. Если вы не можете достичь СУХОЙ ( когда это действительно применимо - отметив ваше редактирование) из-за структуры вашего приложения, это явный признак того, что структура стала пассивом. Вот почему «постоянный рефакторинг» также является основным принципом.
АВС других конструктивных принципалов (тверды, сухи и т.д.) вне там все используемые , чтобы сделать изменения ( в том числе рефакторинга) приложения более безболезненным. Сосредоточьтесь на этом , и все другие проблемы начинают исчезать.
источник
У меня другое мнение, по крайней мере, для третьего варианта:
Из вашего описания:
Помещение F в модуль C не увеличивает сцепление, так как A и B уже нуждаются в функции C.
источник