Должны ли реализации интерфейса быть независимыми
Я натолкнулся на какой-то унаследованный код, который поднял все мои шкуры как объектно-ориентированный программист.
Вот часто используемый шаблон:Интерфейс имеет две реализации, и одна реализация вызывает метод другой.
Теперь я думаю, что это следует изменить, чтобы реализации не знали друг о друге. Это достаточно просто, КАК это сделать. То, что я не могу понять ясно - и надеюсь, что хорошие люди из СО помогут мне - это ПОЧЕМУ.
Я вижу теоретическую причину - это ужасный объектно-ориентированный дизайн. Но я играю здесь адвоката дьявола и спрашиваю - каков практический недостаток двух реализаций, имеющих знание друг о друге. Почему нужно тратить время и деньги, чтобы избавиться от этого (на мой взгляд) анти-паттерна?
Любая информация или ссылки на это будут оценены.
4 ответа
Нет ничего плохого в том, что реализация1 интерфейса1 осознает или взаимодействует с реализацией2 интерфейса1.
Я думаю, что вы только что обнаружили предполагаемую или непреднамеренную реализацию шаблона прокси http://en.wikipedia.org/wiki/Proxy_pattern
Надеюсь это поможет:)
Я вижу теоретическую причину - это ужасный объектно-ориентированный дизайн.
Зачем? Это звучит вполне разумно для меня.
Например, предположим, что я хочу украсить каждый вызов - например, добавить статистику о частоте выполнения вызова, добавить проверку авторизации и т. Д. Имеет смысл отделить это оформление от реальной реализации и просто делегировать:
public class DecoratedFoo : IFoo
{
private readonly IFoo original;
public DecoratedFoo(IFoo original)
{
this.original = original;
}
public string Bar() // Defined in IFoo
{
// Update statistics here, or whatever
return original.Bar();
}
}
Почему вы считаете такое разделение интересов "ужасно объектно-ориентированным дизайном"? Даже если оформленный класс знает о конкретной реализации IFoo
и называет членов, которые не являются частью IFoo
Само по себе, чтобы сделать вещи более эффективными, мне это не кажется особенно ужасным. Это просто один класс, который знает о другом, и они реализуют один и тот же интерфейс. Они более тесно связаны, чем в примере выше, который знает только о IFoo
, но это все же не "ужасно".
Этот метод "другой реализации", который вызывает первая реализация, я бы назвал библиотечной функцией. Поместите его в отдельный модуль / файл / проект / что угодно (зависит от вашего языка /dev env) и включите его в обе реализации и используйте его оттуда.
Нет абсолютно ничего плохого в двух реализациях некоторого интерфейса, содержащих общий код, но, конечно, этот общий код, вероятно, следует отделить от каждой реализации, чтобы вы могли загрузить любую из них в свою программу без необходимости загружать другую.
Мои мысли по этому поводу
Предположим, со временем, если вы удалите одну реализацию и сохранили ее отдельно, в другой не произойдет никаких изменений, и вам не нужно будет это проверять. Если нет разделения, вам нужно потратить время на разделение и тестирование другой реализации.
Всегда чище иметь единственную ответственность.