Конкретные классы против интерфейсов: когда использовать?
Я хорошо осведомлен о преимуществах интерфейсов и о том, как они помогают объединять общие функциональные возможности аналогичных типов объектов. Однако я полагаю, что люди слишком далеко отнеслись к этой "всегда программе к интерфейсу".
а) Люди, начинающие с ВСЕГДА, определяющие интерфейс, а затем реализующие его в классе, даже если этот интерфейс слишком специфичен для реализации любым другим классом. - Я единственный, кто считает, что это бесполезно?
b) Принудительный вывод всех "связанных" интерфейсов для общего (бесполезного) интерфейса, поскольку теперь он "расширяемый". Что?
c) Что вы делаете в сценариях, где два или более объекта кажутся связанными, но очень сложно определить общие методы интерфейса из-за его основных отличий?
Скажем, например, интерфейс с именем IConnection
с Connect()
метод. (так большинство примеров упрощают интерфейсы). Проблема заключается в том, что для разных типов классов, реализующих интерфейс IConnection, могут потребоваться разные данные для установления соединения, для некоторых могут потребоваться имя пользователя и пароль, для некоторых может потребоваться какой-то особый ключ подключения, для некоторых вообще может не потребоваться ничего. Connect
Метод как контракт является вполне допустимым, так как каждому классу потребуется определенный способ установления соединения, но данные, которые ему нужны, различны.
Нужен ли интерфейс в этом случае? Если это так, как вы определяете Connect
метод? Если нет, как вы докажете, что ваши конкретные классы все еще "расширяемы"?
Извините за длинную напыщенную речь, это беспокоило меня уже довольно давно. Большинство людей после прочтения знаменитой книги о шаблонах проектирования стараются внедрить все возможные шаблоны во все, что они делают, не задумываясь, поможет ли это. Я считаю, что модель должна быть задействована, когда вы столкнулись с проблемой не только из-за нее.
1 ответ
В вашем примере IConnection вы в основном описываете абстрактный метод Connect(), так как каждый класс должен будет реализовать свою собственную версию. Обычно (всегда?) Абстрактные методы могут быть определены только с одними и теми же параметрами, поэтому Connect (имя пользователя, пароль) и Connect (ключ) не могут быть реализациями одного и того же метода Connect() из интерфейса.
Теперь, на этом этапе, вы можете определить его как IConnection::Connect(SomeConnectionData) и получить UsernamePasswordConnectionData, KeyConnectionData и т. Д. И т. Д. Из этого класса SomeConnectionData, но все это будет так сложно объяснить и реализовать, что это довольно хорошая подсказка, что интерфейсы и наследование не помогают ситуации.
Если это усложняет программирование и использование, не делайте этого. Если что-то делается "расширяемым", становясь слишком сложным для понимания, в любом случае это не будет расширяться. Совершенно нормально определить группу классов, каждый из которых имеет свои собственные методы Connect(), просто как соглашение.