2010-10-27 6 views
3

Я использовал множество абстрактных классов как для полиморфизма, так и, очевидно, наследуя общую функцию в подклассах.Better Grasp on Interfaces

Я пытаюсь использовать интерфейсы больше. Да, это также используется для полиморфизма ... например, с использованием параметра IMyInterface в методе, который может принимать любой подкласс, который реализует IMyInterface.

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

Пример, посмотрите на эту статью:

http://weblogs.asp.net/sfeldman/archive/2008/02/14/understanding-ioc-container.aspx

Хорошо, в частности, это:

17:  private static void AppCode() 
    18:  { 
    19:  ConsoleLogger logger = new ConsoleLogger(); 
    20:  Gadget gadget = new Gadget(logger); 
    21:  gadget.TurnOn(); 
    22:  gadget.TurnOff(); 
    23:  } 
    24: } 
    25: } 

AppCode method (lines 19-22) is what we are interested in. A few question can be raised at this point: 

    1. Why logger is of type ConsoleLogger and not ILogger? Isn't this wrong? 
    2. Why gadget is of type Gadget and not IGadget? Same smell? 
    3. What if we need to move logger implementer to a different layer than the ConsoleApp? 

Вот что для меня, я не понимаю, почему это не проблема просто использовать конкретные методы Gadget и ConsoleLogger. Почему в этом верхнем слое все еще нужно быть var типа ILogger и IGadget? Я имею в виду, что на данный момент я не вижу необходимости в полиморфизме ... но я не вижу лодку, на мой взгляд, здесь, в моем учебном процессе.

Может кто-нибудь объяснить, почему каждый хочет создать параметры интерфейса в верхних слоях для переменные и присваивание этой переменной типу, который реализовал этот интерфейс? Почему не только Gadget и ConsoleLogger - это самый конкретный класс, который вы хотите использовать в первую очередь? Да Gadget и ConsoleLogger соответствуют контрактам ILogger и IGadget ... но Я должен упустить другую причину здесь. Основная причина.

Если у меня нет смысла, это потому, что я действительно не знаю, как описать свой вопрос, но я чувствую, что это довольно ясно. Зачем использовать интерфейсные переменные в случае как это?

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

ответ

6

Вот что для меня, я не понимаю, почему это не проблема, просто используйте конкретные методы Gadget и ConsoleLogger. Почему в этом верхнем слое все еще нужно быть var типа ILogger и IGadget? Я имею в виду в данный момент я не вижу никакой необходимости в polymorphism..but я "м упускаю я думаю здесь, в моем учебном процессе.

Вся идеей inversion of control является получение зависимостей из ряда классы, которые используют их Accodring код, который вы вставили. - Program сильно связан с определенными классами я даже говорю. - он связан с implementation

Итак, когда вы переписать, что Program на использование интерфейсов - вы в будущем вы сможете использовать любую имплантацию интерфейса. Предположим, вы хотели изменить ConsoleLogger на SyslogLogger или даже на CompositeLogger, которые пишут с несколькими хранилищами.

С зависимыми инвертированными (перемещенными вне класса) - вы можете сделать это очень просто и без каких-либо изменений. Как обычно - конфигурация контейнера зависимостей - это, например, некоторый формат для чтения, xml. Поэтому для изменения поведения вашей программы (переход от одного к другому регистратору) - вам нужно всего лишь изменить одну строку в файле конфигурации.

http://en.wikipedia.org/wiki/Inversion_of_control - эта статья описывает то же самое, но в правильном английском))

UPD:

в этом образце - Program зависит от ConsoleLogger класса. Это означает, что зависимость «внутри» программы класса. Поэтому, когда вы перемещаете эту зависимость снаружи (например, передавая ConsoleLogger по функциональному параметру) - она ​​называется инверсия. И теперь эта зависимость находится вне. Снаружи == Program теперь зависит от некоторого интерфейса ConsoleLogger, а не от самого класса, и теперь Program не заботится о том, как создать экземпляр этого объекта класса.

И dependency container - это просто программное обеспечение, которое поможет вам организовать отношения/зависимости удобным способом (как обычно это дерево, дерево зависимостей).

+0

спасибо. Я не понимаю, что вы подразумеваете под «получить зависимости от классов, которые их используют» – PositiveGuy

+0

(Предположим, вы хотели изменить ConsoleLogger на SyslogLogger или даже на CompositeLogger, который пишет в несколько хранилищ). Хорошо, поэтому вы говорите, что если я захочу перейти на другой журнал, то после того, как я уже выполнил регистрацию ILogger = new ConsoleLogger, я мог бы взять эту переменную регистратора и сделать logger = новый SyslogLogger, и теперь эта переменная указывает на новый тип регистратора через полиморфизм, поскольку SyslogLogger реализует ILogger? – PositiveGuy

+0

@CoffeeAddict: добавлен ответ на 1-й комментарий – zerkms