Существуют ли альтернативы ISomething / ISomethingable для интерфейсов?

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

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

На самом деле это считается ПЛОХОЙ практикой в ​​java. См. «Эффективная Java» Джошуа Блоха. Это здорово, но также довольно печально, что C# все еще его использует.

Andriy Drozdyuk 21.09.2010 05:53

@drozzy, (или кто-нибудь его читал) - вы помните, где Дж. Блох обсуждал эту тему (я имею в виду страницу)? У меня есть второе издание этой книги, и я не могу найти никаких ссылок на соглашение об именах «Я».

greenoldman 08.10.2013 12:36

@greenoldman Хороший вопрос, он на самом деле не говорит, что это «плохо», просто не упоминает об этом. См. Стр. 237-238 Эффективная Java 2nd. Простите за мое чрезмерное рвение.

Andriy Drozdyuk 09.10.2013 17:57
БЭМ: Конвенция об именовании CSS
БЭМ: Конвенция об именовании CSS
Я часто вижу беспорядочный код CSS, особенно если проект большой. Кроме того, я совершал эту ошибку в профессиональных или личных проектах и...
11
3
1 800
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

В стандарте кодирования для Symbian есть интерфейсы (чистые абстрактные классы C++), обозначенные буквой M, а не I.

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

Что касается .NET, книга Microsoft Framework Design Guidelines абсолютно рекомендует это, и да, это очень стандартно. Я никогда не видел, чтобы это было иначе, и создание нового соглашения только запутает людей.

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

переменные класса с префиксом _ раздражают меня в C++. _ предназначен для обозначения системных переменных и библиотек, а не переменных класса.

workmad3 21.10.2008 20:22

Что касается C++, я с вами согласен. Мне они нравятся специально для C#.

Neil 21.10.2008 21:41

Все дело в стиль и читаемость. Добавление к интерфейсам префикса «I» - это просто соглашение об именах и руководство по стилю, которое прижилось. Сами компиляторы не заботятся об этом.

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

Scott Dorman 21.10.2008 20:21

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

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

Одна небольшая информация: я довольно много работаю как с Java, так и с C#, и мне регулярно приходится проверять, какие типы в Java на самом деле являются интерфейсами, особенно в рамках структуры сбора. .NET просто упрощает это. Может быть, это не беспокоит других, но беспокоит меня.

+1 для IFoo от меня.

Я не понимаю, почему так много людей считают полезным отличать интерфейсы от других типов с помощью именования типов. Современная IDE поместит красивый значок рядом с именем файла. Кроме того, если вы не знакомы с типом, скорее всего, вам все равно придется открыть его и прочитать исходный код / ​​документацию.

i3ensays 02.08.2013 22:14

@ i3ensays: «Рядом с именем файла» предполагает, что вы просматриваете его в браузере пакетов или в другом месте. Я бы предпочел не предпринимать никаких действий, когда просто чтение кода. Да, я могу все посмотреть, но не хочу. Это определенно субъективная вещь, но мне нравится соглашение .NET для этого.

Jon Skeet 02.08.2013 22:26

это, вероятно, зависит от вашего текстового редактора / IDE, но intellisense в коде довольно хорошо справляется с различиями для меня. Например, когда я набираю «новый» при объявлении присваивания, я могу автоматически завершить присвоение со всеми известными реализующими типами, отображаемыми в подконтекстном меню.

i3ensays 14.09.2013 03:27

@ i3ensays: Вот когда вы получаете код пишу. Я трачу больше времени на код чтение, чем на его написание ... и большую часть этого времени я уделяю представлениям различий и т. д., А не IDE.

Jon Skeet 14.09.2013 12:17
Ответ принят как подходящий

Из книги Framework Design Guidelines:

Interfaces representing roots of a hierarchy (e.g. IList) should also use nouns or noun phrases. Interfaces representing capabilities should use adjectives and adjective phrases (e.g. IComparable, IFormattable).

Также из аннотаций по именованию интерфейсов:

KRZYSZTOF CWALINA: One of the few prefixes used is “I” for interfaces (as in ICollection), but that is for historical reasons. In retrospect, I think it would have been better to use regular type names. In a majority of the cases developers don’t care that something is an interface and not an abstract class, for example.

BRAD ABRAMS: On the other hand, the “I” prefix on interfaces is a clear recognition of the influence of COM (and Java) on the .NET Framework. COM popularized, even institutionalized, the notation that interfaces begin with “I.” Although we discussed diverging from this historic pattern we decided to carry forward the pattern as so many of our users were already familiar with COM.

JEFFREY RICHTER: Personally, I like the “I” prefix and I wish we had more stuff like this. Little one-character prefixes go a long way toward keeping code terse and yet descriptive. As I said earlier, I use prefixes for my private type fields because I find this very useful.

BRENT RECTOR Note: this is really another application of Hungarian notation (though one without the disadvantages of the notation's use in variable names).

Он стал широко принятым стандартом, и, хотя он является разновидностью венгерского языка, как утверждает Брент, он не страдает недостатками использования венгерской нотации в именах переменных.

Ого, какие-то умные ребята. В частности, я большой поклонник Брэда Абрамса.

Robert S. 05.01.2009 23:40

Как .NET-программист (по большей части), я предпочитаю соглашение Java об отказе от I здесь по простой причине: часто небольшие переделки требуют перехода от интерфейса к абстрактному базовому классу или наоборот. Если вам нужно изменить имя, это может потребовать большого количества ненужного рефакторинга.

С другой стороны, использование для клиента должно быть прозрачным, чтобы он не обращал внимания на подсказку этого типа. Более того, суффикс «способный» в слове «Thingable» должен быть достаточным намеком. Он достаточно хорошо работает на Java.

/ Обновлено: Я хотел бы отметить, что приведенные выше рассуждения побудили меня отказаться от префикса I для частных проектов. Однако, проверив один из них на соответствие набору правил FxCop, я сразу же вернулся к использованию I. Здесь выигрывает согласованность, хотя глупая последовательность - хобгоблин маленьких умов.

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

Andriy Drozdyuk 21.09.2010 05:55

@drozzy: Согласованность всегда диктует практику программирования. А аргумент о «скользкой дорожке» - логическая ошибка. Фактически, если вы хотите разработать многоразовый API для языка программирования, вы оправдываете ожидания. API должен быть простым в использовании, а это значит, что он должен соответствовать тому, что пользователь уже знает. являются причины нарушить это правило, но глупый I перед именем класса не является одним из них. Я считаю, что соглашение Microsoft об именах глупо, но поезд отошел от станции.

Konrad Rudolph 21.09.2010 12:24

Согласованность в API мне больше нравится. Если вы хотите быть совместимым с другими API, я согласен, вы должны соответствовать. Но если вы работаете над проектом независимо и постоянно отказываетесь от префикса I, почему бы и нет? На самом деле, почему бы не научить НОВЫХ программистов отказываться от этого ...

Andriy Drozdyuk 21.09.2010 17:32

@drozzy: ну, проект каждый .NET использует API .NET framework. И это использует I в качестве префикса интерфейса. Кроме того, ни один настоящий проект не является полностью независимым от остальных, рано или поздно проект может вырасти настолько, что ему потребуется взаимодействовать с другими существующими API. И каждый код должен быть написан с расчетом на будущее, поскольку вы никогда не знаете, будет ли этот код в будущем использоваться где-то еще или ему нужно будет взаимодействовать с чужим кодом. Платформа .NET в основном диктует все основные соглашения для использования в других проектах .NET.

Konrad Rudolph 21.09.2010 18:03

Я не понимаю, что будет, если ребята из Microsoft решат не использовать его в .net 5.0.

Andriy Drozdyuk 21.09.2010 23:05

Что ж, в java это проще - поскольку он специально различает чистые интерфейсы (реализует) и абстрактные классы (расширяет). Что делает INotation бесполезным imho. .NET этого не делает - поэтому, хотя в java у нас есть «Адаптер реализует Observable extends BaseAdapter», в .NET это может сбивать с толку «Адаптер: Observable, BaseAdapter».

Andriy Drozdyuk 15.11.2010 20:29

Хотя C# может использовать аналогичный синтаксис для реализации интерфейсов и наследования классов, они являются семантически разными концепциями и, следовательно, имеют разные правила. Часто бывает необходимо иметь тесно связанный интерфейс и класс (например, IEnumerable<T> и Enumerable<T>). Если в именах интерфейсов не было префикса «I», тогда то, что сейчас называется IEnumerable<T>, было вместо Enumerable<T>, где можно ожидать найти то, что теперь называется Enumerable<T>.Empty? Кстати, интересно, почему «I» в верхнем регистре? Ненависть к Apple? iMutableFnord кажется более ясным, чем IMutableFnord.

supercat 03.04.2012 19:09

@supercat Enumerable - это не абстрактный базовый класс, это нечто совершенно иное. И нет никакой проблемы в конфликте имен. Если вы настаиваете на использовании того же имени (но почему?), Вы всегда можете поместить класс в другое пространство имен. И I - это прописные буквы, чтобы соответствовать соглашению об именах PascalCase. В конце концов, это не Java, поэтому нет причин делать I строчными буквами.

Konrad Rudolph 03.04.2012 19:51

@KonradRudolph: Enumerable не является абстрактным базовым классом, но статические члены, такие как Empty, не могут быть частью интерфейса; если бы интерфейс назывался Enumerable, какое было бы «очевидное» имя для тесно связанного статического класса? Что касается именования PascalCase / camelCase, я думаю, что префиксы следует рассматривать как отличные от «слов».

supercat 03.04.2012 20:08

@supercat А как насчет EnumerableHelpers, EnumerableExtensions или EnumerableMixin? В конце концов, вот что это такое.

Konrad Rudolph 03.04.2012 20:25

@drozzy: Тот факт, что C# использует ту же нотацию для наследования классов и реализации интерфейса, является делом C#, а не .NET; в .NET framework они обрабатываются по-разному, и не все языки соответствуют рекомендациям C# (я знаю, что VB.NET использует разные ключевые слова для Inherits и Implements). Гораздо большее значение имеют некоторые семантические различия со стороны потребителя между абстрактными классами и интерфейсами, которые существуют в .NET, но не актуальны в Java. Универсальный тип, ограниченный абстрактным классом, всегда будет ссылочным типом, но тип, ограниченный интерфейсом, не может.

supercat 27.08.2013 02:53

Поскольку все непримитивные типы в Java являются ссылочными типами, такие различия не имеют значения на этом языке / платформе, но на такой платформе, как .NET, которая включает непримитивные типы значений, они могут быть очень важны.

supercat 27.08.2013 02:55

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

public class CustomerImpl implements Customer

Но как мы узнаем, что Customer - это интерфейс, а не, скажем, абстрактный класс?

Robert S. 05.01.2009 23:40

Я думаю, что суффикс «Impl» затрудняет чтение кода, чем префикс «I» в интерфейсе, особенно для общедоступных API.

Scott Dorman 07.01.2009 22:53

@RobertS. почему тебя это волнует? серьезно.

i3ensays 02.08.2013 22:20

@ScottDorman некоторые могут упомянуть списки порядка сортировки внутри пакета (реализация, скорее всего, упадет сразу после интерфейса), но я согласен, суффикс неприятный и предпочел бы видеть детали реализации, добавленные к имени префикса (например, PremiumCustomer)

i3ensays 02.08.2013 22:23

Вы просили альтернативу, поэтому вот одна из тех, с которыми я столкнулся:

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

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

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

Мое главное предположение состоит в том, что самое главное - поддерживать читаемость в доменной части реализации. Следовательно:

  • Если у вас есть одно поведение и одна возможная реализация, просто не создавайте интерфейс:

    public class StackOverflowAnswerGenerator { }

  • Если у вас есть одно поведение и множество возможных реализаций, тогда нет проблем, и вы можете просто отбросить «Я» и получить:

    public interface StackOverflowAnswerGenerator {}

    public class StupidStackOverflowAnswerGenerator : StackOverflowAnswerGenerator {}

    public class RandomStackOverflowAnswerGenerator : StackOverflowAnswerGenerator {}

    public class GoogleSearchStackoverflowAnswerGenerator : StackOverflowAnswerGenerator {}

    //...

  • Настоящая проблема возникает, когда у вас есть одно поведение и одна возможная реализация, но вам нужен интерфейс для описания его поведения (например, для удобного тестирования из-за соглашения в вашем проекте, с использованием некоторой библиотеки / фреймворка, который это обеспечивает, ...). Возможные решения, кроме префикса интерфейса:

    а) Префикс или суффикс реализации (как указано в некоторых других ответах в этой теме)

    б) Используйте другое пространство имен для интерфейса:

    namespace StackOverflowAnswerMachine.Interfaces 
    {
      public interface StackOverflowAnswerGenerator {}
    }
    
    namespace StackOverflowAnswerMachine 
    { 
      public class StackOverflowAnswerGenerator : Interfaces.StackOverflowAnswerGenerator
    {}
    
    }
    

    в) Используйте другое пространство имен для реализации:

    namespace StackOverflowAnswerMachine 
    {
      public interface StackOverflowAnswerGenerator {}
    }
    
    namespace StackOverflowAnswerMachine.Implementations 
    { 
      public class StackOverflowAnswerGenerator : StackOverflowAnswerMachine.StackOverflowAnswerGenerator 
    {}
    
    }
    

Хотя я думаю, что последняя возможность является наиболее чистой, ее единственный недостаток состоит в том, что, хотя using StackOverflowAnswerMachine; дает вам доступ ко всем объектам домена, вы должны префикс всех интерфейсов домена, чтобы не путать их с их реализациями. Это может показаться чем-то не очень удобным, но в чистом дизайне обычно класс не использует многие другие объекты домена, и в основном вам нужно использовать префикс только в объявлении поля и списке параметров конструктора. Итак, это моя текущая рекомендация.

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

Другие вопросы по теме