Как интерфейс может быть полностью независимым от реализации, если мы должны указать параметры метода - PullRequest
0 голосов
/ 25 июля 2011

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

Это кажется особенно проблематичным в области Inversion Of Control, где компонент более высокого уровня, кажется, «владеет» интерфейсом. Насколько я понимаю, компонент более высокого уровня в основном говорит: мне нужен компонент низкого уровня для выполнения некоторых функций. Вот функции, которые мне нужны (в форме интерфейса), а затем другой класс может предоставить эту услугу бесплатно.

Но как опубликовать этот интерфейс, как компонент верхнего уровня узнает, какие параметры понадобятся разработчику?

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

Есть ли какая-то абстракция, которая решает эту проблему? Должны ли мы просто «чрезмерно параметризировать» сигнатуры методов в наших интерфейсах и позволить разработчику игнорировать аргументы, которые ему не нужны? Или мы должны всегда иметь параметры no и позволить разработчику иметь дело с получением того, что ему нужно откуда-то еще?

ОБНОВЛЕНИЕ: Позвольте мне привести конкретный пример. Допустим, у меня есть LightController, который реализует интерфейс с методом Detect () или что-то в этом роде. Я компонент "Комната" более высокого уровня, и я хочу, чтобы он включал свет, когда кто-то входит в комнату. Какие параметры я определяю как часть сигнатуры обнаружения? Что, если я передам его в параметр Sound, чтобы источники света могли переключаться в зависимости от уровня звука? Но, черт возьми, есть класс, который хочет реализовать это с помощью обнаружения движения, а не звука. И мне действительно все равно, так или иначе. Так что мне просто нужно пройти через все состояние комнаты и позволить разработчику решить, что ему нужно?

ОБНОВЛЕНИЕ2: Позвольте мне быть более точным с кодом:

interface ILightController {
   bool Detect(paramIThinkImplementorWillNeed);
}

class Room {
   ILightController lc = GetService(ILightController);
   if (lc.Detect(thatParam))
   ...
}

class MovementLightController : NOTILightController {  // nope
   public bool Detect(aDifferentParam) {
      // i could very well have fulfilled this functionality but the  
      // interface does not allow for the input i need. that's too bad.
   }
}

Я думаю, что одним из решений было бы, если бы "контракт" шел в обе стороны. Что, если вызывающая сторона методов ILightController должна была удовлетворять другой интерфейс, который накладывал ограничения на it , а затем передавал себя каждому методу интерфейса LightController, из которого контроллеры освещения могли бы получить вход, который им нужен. Итак:

interface ILightControllerInput {
   public PropertyNeededByImplementorsOfILightController { get; set; }
}

interface ILightController {
   public Detect(ILightControllerInput input);
   public SomeOtherMethod(ILightControllerInput input);
   // etc..
}

class Room : ILightControllerInput {
   public PropertyNeededByImplementorsOfILightController { get; set; }
   ILightController lc = GetService(ILightController);

   if (lc.Detect(this)) ...
}

class MovementLightController : ILightController {
   public bool Detect(ILightControllerInput input) {
      // that's right baby, it's a 2-way street here. if i'm going to conform
      // to your interface, you're going to conform to what i need!
   }
}

И затем из этого вы можете получить реализацию служб, которая идет в обе стороны. Компонент более высокого уровня может найти компонент более низкого уровня, который реализует интерфейс, который ему необходим, но компонент более высокого уровня должен указать, какие входные данные он может передавать, и который будет соответствовать подмножеству доступных компонентов низкого уровня (поэтому «удовлетворение потребностей» идет в обе стороны).

Пожалуйста, скажите мне, я курю крэк? Или что-то подобное уже существует (как шаблон и т. Д.)?

Ответы [ 5 ]

2 голосов
/ 25 июля 2011

Да, это обязательно показывает некоторые подсказки. Нужно, это красивый ключ здесь. Если я создаю интерфейс для чего-то, что предназначено для того, чтобы брать изображения и загружать / сохранять их откуда-то, по крайней мере мне нужно знать, какое изображение загрузить и какие данные сохранить (и какой ключ использовать, чтобы я мог загрузить его еще раз позже).

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

«Сокрытие всех деталей реализации» - это идеал. На самом деле мы не всегда добираемся туда. :)

1 голос
/ 25 июля 2011

Да, интерфейсы должны отделять и скрывать реализацию. Тем не менее, они также определяют контракт, то есть: вход и выход. Чтобы это работало, нужно знать, каков ожидаемый вклад и каков ожидаемый результат. Скрытие реализации - это то, что находится между ними, преобразование ввода в вывод.

1 голос
/ 25 июля 2011

Вы должны тщательно решить, к каким интерфейсам вы собираетесь абстрагироваться.Это все о принятии правильных дизайнерских решений при создании вашей системы.В этом случае interface в C # или .NET определяется методами, которые он предоставляет.Эти методы имеют подписи, так как они являются возвращаемыми значениями и параметрами, которые они принимают, имя метода также имеет значение.

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

Вы не можете больше отделить это, иначе что вы собираетесь оставить для определения?Должна быть какая-то точка входа в ваше общение между вашими клиентами и вашим кодом.Интерфейс является той точкой связи.Это говорит вашим клиентам, что он собирается делать, и это все, что он говорит, а не как , просто что

1 голос
/ 25 июля 2011

Параметры считаются частью интерфейса. На самом деле они ничего не говорят вам о реализации.

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

0 голосов
/ 25 июля 2011

Если для реализации нужны некоторые специфические для реализации аспекты, они должны быть переданы во время инициализации и, вероятно, должны быть в конструкторе. В этом и заключается суть IoC: вам не нужно знать подробности, только важные части.

Например, представьте, что у вас есть IWageProcessor, у которого есть метод decimal GetWage(Employee employee). Ничто в этом методе не зависит от конкретной реализации. Если для реализации IWageProcessor нужно что-то еще (например, соединение с базой данных), IoC позаботится об этом. Если вы хотите изменить реализацию IWageProcessor, чтобы она не использовала базу данных, а WCF, вы можете сделать это, и интерфейс не изменится.

Это не значит, что интерфейс никогда не изменится. Но если это меняется, то только тогда, когда меняется значение методов, а не только реализация. Например, если было решено, что получить текущую заработную плату недостаточно, и нам нужно рассчитать заработную плату на основе месяца, метод можно изменить на decimal GetWage(Employee employee, Month month). Это, конечно, изменит реализацию, но это не наоборот. Если реализация изменилась, но смысл не изменился, интерфейс остался бы прежним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...