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


Что я обычно делаю, так это создаю пространство имен Interfaces на высоком уровне в моей иерархии и помещаю туда все интерфейсы (я не беспокоюсь о том, чтобы вкладывать туда другие пространства имен, поскольку в результате у меня будет много пространств имен, содержащих только один интерфейс).
Interfaces
|--IAnimal
|--IVegetable
|--IMineral
MineralImplementor
Organisms
|--AnimalImplementor
|--VegetableImplementor
Именно так я делал это в прошлом, и у меня не было много проблем с этим, хотя, по общему признанию, это может сбивать с толку других, сидящих за моими проектами. Мне очень любопытно посмотреть, что делают другие люди.
Обычно я сохраняю интерфейс в том же пространстве имен, что и конкретные типы.
Но это только мое мнение, а структура пространства имен очень субъективна.
Animals
|
| - IAnimal
| - Dog
| - Cat
Plants
|
| - IPlant
| - Cactus
На самом деле вы ничего не получите, переместив один или два типа из основного пространства имен, но вы добавите требование для одного дополнительного оператора using.
Ответ зависит от ваших намерений.
Я уверен, что есть и другие варианты, но, как и в случае с большинством проблем с пространством имен, все сводится к вариантам использования проекта, а также к классам и интерфейсам, которые он содержит.
(.Net) Я обычно храню интерфейсы в отдельной «общей» сборке, поэтому я могу использовать этот интерфейс в нескольких приложениях и, чаще, в серверных компонентах моих приложений.
Что касается пространств имен, я храню их в BusinessCommon.Interfaces.
Я делаю это для того, чтобы ни у меня, ни у моих разработчиков не возникло соблазна ссылаться на реализации напрямую.
Я тоже так делаю. У него есть дополнительный побочный эффект, заключающийся в возможности иметь «циклические ссылки» с использованием внедрения зависимостей: Foo зависит от Bar, Bar зависит от IFoo (который находится в общей сборке), а Foo вводится в Bar через DI. вуаля.
Разделите интерфейсы каким-либо образом (проекты в Eclipse и т. д.), Чтобы было легко развернуть только интерфейсы. Это позволяет вам предоставлять внешний API без предоставления реализаций. Это позволяет создавать зависимые проекты с минимальным количеством внешних элементов. Очевидно, это больше относится к более крупным проектам, но концепция хороша во всех случаях.
Я предпочитаю хранить свои интерфейсы и классы реализации в одном пространстве имен. Когда возможно, я даю классам реализации внутреннюю видимость и предоставляю фабрику (обычно в виде статического фабричного метода, который делегирует рабочему классу, с внутренним методом, который позволяет модульным тестам в дружественной сборке заменять другого рабочего, который производит заглушки). Конечно, если конкретный класс должен быть общедоступным - например, если это абстрактный базовый класс, тогда это нормально; Я не вижу причин помещать ABC в собственное пространство имен.
Кстати, мне очень не нравится соглашение .NET, согласно которому имена интерфейсов начинаются с буквы «I.». Модель интерфейса (I) Foo - это не ifoo, это просто фу. Так почему я не могу назвать это просто Фу? Затем я конкретно называю классы реализации, например, AbstractFoo, MemoryOptimizedFoo, SimpleFoo, StubFoo и т. д.
Тат довольно сложен, хотя я понимаю, насколько это эффективно. Я также всегда задавался вопросом, почему люди ворчали по поводу I ... конвенции, что на самом деле имеет смысл
Все просто: ваш foo - это не Foo, а вообще просто реализация своей части. Когда конкретная реализация IFoo просто реализует IFoo и ничто иное не является просто подслучайным случаем, зачем создавать отдельные правила для статистически незначимого подслучайного случая? Интерфейс похож на точку доступа к некоторым функциям класса, реализующего интерфейс. То же самое можно сказать и об объекте foo - это как панель управления для какого-то конкретного объекта, а не сам объект.
Я обычно разделяю их на две отдельные сборки. Одна из обычных причин создания интерфейса - это то, что ряд объектов выглядит одинаково для некоторой подсистемы вашего программного обеспечения. Например, у меня есть все мои отчеты, реализующие интерфейсы 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 МБ только для двух тупых подписантов!
Вы держали меня до последнего предложения, что, кажется, противоречит остальной части вашего ответа. Хотите уточнить?
Я привожу свой собственный опыт, который противоречит другим ответам.
Я стараюсь помещать все свои интерфейсы в пакет, к которому они принадлежат. Это означает, что если я перемещаю пакет в другой проект, у меня есть все необходимое для запуска пакета без каких-либо изменений.
Для меня любые вспомогательные функции и операторные функции, которые являются частью функциональности класса, должны входить в то же пространство имен, что и класс, потому что они составляют часть общедоступного API этого пространства имен.
Если у вас есть общие реализации, которые используют один и тот же интерфейс в разных пакетах, вам, вероятно, потребуется реорганизовать свой проект.
Иногда я вижу, что в проекте есть множество интерфейсов, которые можно преобразовать в абстрактную реализацию, а не в интерфейс.
Итак, спросите себя, действительно ли вы моделируете тип или структуру.
Что произойдет, если я захочу использовать другой класс Dog из другого пространства имен? Я думаю, что не рекомендуется иметь интерфейсы и реализацию в одном пространстве имен.