Префиксирование интерфейсов с I? - PullRequest
26 голосов
/ 28 апреля 2011

В настоящее время я читаю «Чистый код» Роберта Мартина (UncleBob) и вообще люблю размышления о UncleBob. Однако, я немного запутался, когда прочитал, что он избегает префиксов интерфейсов, таких как «IPerson». Он заявляет: «Я не хочу, чтобы мои пользователи знали, что я передаю им интерфейс».

Размышляя о перспективе TDD / инъекции, мне всегда будет очень интересно рассказать «пользователям» моих классов, что я передаю интерфейс. Основная причина заключается в том, что я рассматриваю контракты интерфейсов между различными "агентами" системы. Агент, работающий с одним углом моей системы, не должен знать конкретную реализацию работы другого агента; они должны только обмениваться контрактами и ожидать, что контракты будут выполнены, не зная как. Другая, но также очень важная причина заключается в том, что интерфейс может быть полностью смоделирован, что значительно упрощает модульное тестирование. Есть пределы тому, сколько вы можете издеваться над конкретным классом.

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

Это неправильно для меня настаивать на том, что я в интерфейсах ??

Ответы [ 3 ]

56 голосов
/ 28 апреля 2011

В Java и C # существует ряд соглашений, с которыми мы привыкли;но это назад.Например, соглашение о размещении частных переменных в начале каждого класса довольно глупо с технической точки зрения.Самое важное в классе - это публичные методы. минимум важных вещей, вещи, которые мы скрываем за барьером конфиденциальности, являются переменными экземпляра.Так зачем нам ставить их сверху?

"I" перед интерфейсами - это еще одно обратное соглашение.Когда вам передают ссылку на объект, вы должны ожидать , что это будет интерфейс.Интерфейсы должны быть по умолчанию;поэтому нет смысла делать что-то дополнительное, например, используя префикс I, чтобы объявить, что вы делаете то, что от вас ожидают все.Было бы лучше (хотя все еще неправильно), если бы мы зарезервировали специальный маркер для условия исключительный для передачи конкретного класса.

Другая проблема с использованием I заключается в том, что (как ни странно) мы используемэто для передачи решения о реализации использования интерфейса.Обычно мы не хотим, чтобы решения по реализации выражались так громко, потому что это затрудняет их изменение.Рассмотрим, например, что может произойти, если вы решили, что IFoo действительно должен быть абстрактным классом, а не интерфейсом.Если вы поменяете имя на Foo или CFoo, или ACFoo?

Я слышу, как вращаются колеса в вашей голове.Вы думаете: «Да, но интерфейсы занимают особое место в языке, и поэтому разумно отметить их специальным соглашением об именах».Это правда.Но целые числа также занимают особое место в языке, и мы их больше не помечаем.Кроме того, спросите себя: почему занимают ли интерфейсы особое место в языке?

Вся идея интерфейсов в Java и C # была неудачной.Разработчики языка могли бы только что использовать абстрактные классы, но их беспокоили трудности реализации множественного наследования.Таким образом, они заключили сделку с самим собой.Они изобрели искусственную конструкцию (то есть интерфейсы), которая обеспечивала бы некоторую мощность множественного наследования, и они ограничивали нормальные классы одиночным наследованием.

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

В следующий раз, когда вы напишите сигнатуру функции, подобную этой:

public void myFunction(IFoo foo) {...}

Спросите себя: «Почему я хочу знать, что автор IFoo использовал слово« интерфейс »? Какая разница для меня, использовал ли он« интерфейс »или« класс »или даже« struct »? его дело, а не мое! Так почему же он заставляет меня узнать свое дело, поставив этого великого «я» перед своим типичным именем? Почему он не застегивает свои заявления и не скрывает своих рядовых от моего лица?"

9 голосов
/ 28 апреля 2011

Если вы говорите о .NET, то интерфейсы с I в начале настолько распространены, что их отбрасывание может запутать всех до чертиков.

Плюс я бы предпочел

public class Foo : IFoo {}

чем

public class FooImpl : Foo {}

Все сводится к личным предпочтениям, и я какое-то время играл с этой идеей, но вернулся к префиксу I. YMMV

7 голосов
/ 28 апреля 2011

Я считаю контракты на интерфейсы между различными "агентами" система. Агент, работающий с одним уголок моей системы, не должен знать конкретная реализация другого работа агентов; они должны только обмениваться контракты, и ожидать, что контракты исполняться, не зная как. другая, но очень важная причина является то, что интерфейс может быть посмешищем полностью, и, таким образом, делая юнит-тестирование намного легче. Есть пределы тому, как много можно издеваться над конкретным классом.

Все это правда - но как это требует соглашения об именах для интерфейсов?

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

...