В какое пространство имен следует помещать интерфейсы относительно их разработчиков?

В частности, когда вы создаете пару интерфейс / разработчик, и нет никаких основных организационных проблем (например, интерфейс должен находиться в другой сборке, т.е. в соответствии с рекомендациями архитектуры s #), есть ли у вас способ организации по умолчанию в вашем пространство имен / схема именования?

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

В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Принцип подстановки Лискова
Принцип подстановки Лискова
Принцип подстановки Лискова (LSP) - это принцип объектно-ориентированного программирования, который гласит, что объекты суперкласса должны иметь...
13
0
4 441
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

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

Interfaces
|--IAnimal
|--IVegetable
|--IMineral
MineralImplementor
Organisms
|--AnimalImplementor
|--VegetableImplementor

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

Обычно я сохраняю интерфейс в том же пространстве имен, что и конкретные типы.

Но это только мое мнение, а структура пространства имен очень субъективна.

Animals
|
| - IAnimal
| - Dog
| - Cat
Plants
|
| - IPlant
| - Cactus

На самом деле вы ничего не получите, переместив один или два типа из основного пространства имен, но вы добавите требование для одного дополнительного оператора using.

Что произойдет, если я захочу использовать другой класс Dog из другого пространства имен? Я думаю, что не рекомендуется иметь интерфейсы и реализацию в одном пространстве имен.

Pavel Hodek 26.04.2012 19:35
Ответ принят как подходящий

Ответ зависит от ваших намерений.

  • Если вы хотите, чтобы потребитель ваших пространств имен использовал интерфейсы поверх конкретных реализаций, я бы рекомендовал разместить ваши интерфейсы в пространстве имен верхнего уровня с реализациями в дочернем пространстве имен.
  • Если потребитель должен использовать оба, разместите их в одном пространстве имен.
  • Если интерфейс предназначен в основном для специализированного использования, например для создания новых реализаций, подумайте о том, чтобы разместить их в дочернем пространстве имен, таком как Design или ComponentModel.

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

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

Что касается пространств имен, я храню их в BusinessCommon.Interfaces.

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

Я тоже так делаю. У него есть дополнительный побочный эффект, заключающийся в возможности иметь «циклические ссылки» с использованием внедрения зависимостей: Foo зависит от Bar, Bar зависит от IFoo (который находится в общей сборке), а Foo вводится в Bar через DI. вуаля.

Manu 29.09.2008 02:12

Разделите интерфейсы каким-либо образом (проекты в Eclipse и т. д.), Чтобы было легко развернуть только интерфейсы. Это позволяет вам предоставлять внешний API без предоставления реализаций. Это позволяет создавать зависимые проекты с минимальным количеством внешних элементов. Очевидно, это больше относится к более крупным проектам, но концепция хороша во всех случаях.

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

Кстати, мне очень не нравится соглашение .NET, согласно которому имена интерфейсов начинаются с буквы «I.». Модель интерфейса (I) Foo - это не ifoo, это просто фу. Так почему я не могу назвать это просто Фу? Затем я конкретно называю классы реализации, например, AbstractFoo, MemoryOptimizedFoo, SimpleFoo, StubFoo и т. д.

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

George Mauer 29.09.2008 04:35

Все просто: ваш foo - это не Foo, а вообще просто реализация своей части. Когда конкретная реализация IFoo просто реализует IFoo и ничто иное не является просто подслучайным случаем, зачем создавать отдельные правила для статистически незначимого подслучайного случая? Интерфейс похож на точку доступа к некоторым функциям класса, реализующего интерфейс. То же самое можно сказать и об объекте foo - это как панель управления для какого-то конкретного объекта, а не сам объект.

jungle_mole 23.09.2015 07:22

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

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

Если вы используете Factory Class для возврата списка доступных отчетов в сборке отчета, то обновление программного обеспечения новым отчетом становится просто вопросом копирования новой сборки отчета поверх оригинала. Вы даже можете использовать Reflection API, чтобы просто сканировать список сборок на предмет любых фабрик отчетов и таким образом создавать свой список отчетов.

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

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

НЕНАВИЖУ, когда нахожу интерфейсы и реализации в одном пространстве имен / сборке. Пожалуйста, не делайте этого, если проект будет развиваться, рефакторинг будет головной болью.

Когда я ссылаюсь на интерфейс, я хочу его реализовать, а не получать все его реализации.

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

Обновлено: @ Джош, я просто прочитал последнее мое предложение, это сбивает с толку! конечно, и класс зависимостей, и тот, который его реализует, ссылаются на интерфейс. Для ясности приведу примеры:

Приемлемо :

Интерфейс + реализация:

namespace A;

   Interface IMyInterface
   {
       void MyMethod();
   }

namespace A;

   Interface MyDependentClass
   {
       private IMyInterface inject;

       public MyDependentClass(IMyInterface inject)
       {
           this.inject = inject;
       }

       public void DoJob()
       {
           //Bla bla
           inject.MyMethod();
       }
   }

Реализующий класс:

namespace B;

   Interface MyImplementing : IMyInterface
   {
       public void MyMethod()
       {
           Console.WriteLine("hello world");
       }
   }

НЕДОПУСТИМО:

namespace A;

   Interface IMyInterface
   {
       void MyMethod();
   }

namespace A;

   Interface MyImplementing : IMyInterface
   {
       public void MyMethod()
       {
           Console.WriteLine("hello world");
       }
   }

И, пожалуйста, НЕ СОЗДАВАЙТЕ проект / мусор для своих интерфейсов! пример: ShittyProject.Interfaces. Вы упустили суть!

Представьте, что вы создали DLL, зарезервированную для ваших интерфейсов (200 МБ). Если бы вам пришлось добавить единый интерфейс с двумя строками кодов, вашим пользователям придется обновить 200 МБ только для двух тупых подписантов!

Вы держали меня до последнего предложения, что, кажется, противоречит остальной части вашего ответа. Хотите уточнить?

Josh Noe 19.08.2013 20:28

Я привожу свой собственный опыт, который противоречит другим ответам.

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

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

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

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

Итак, спросите себя, действительно ли вы моделируете тип или структуру.

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