Подходящее пространство имен для многих конкретных реализаций абстрактного класса

#c# #.net #namespaces

#c# #.net #пространства имен

Вопрос:

Я нахожусь в процессе разработки библиотеки .NET и ищу некоторые отзывы относительно организации классов и пространств имен.

Предположим, что у меня есть абстрактный Message класс, который находится в корневом пространстве имен Foo . Message имеет много конкретных реализаций для разных типов сообщений. Учитывая, что будет много конкретных реализаций (предположим, 20 или даже больше), ожидается ли, что эти конкретные типы будут находиться в отдельном пространстве имен, что-то вроде Foo.Messages ?

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

Редактировать:

Кроме того, если я сгруппирую конкретные классы в Foo.Messages , должен ли абстрактный класс также находиться там или он должен остаться в Foo ?

Ответ №1:

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

Группировка всех конкретных классов реализации в пространстве имен Foo.Messages звучит неплохо. Вы также не хотите заходить слишком далеко другим путем — создание множества пространств имен для второстепенных вещей вызывает огромное раздражение у пользователя.

Комментарии:

1. Message Конкретные классы имеют внутренние конструкторы, поэтому они не могут быть созданы вне MessageFactory . Однако сами классы являются общедоступными, потому что в настоящее время у меня есть шаблон, который позволяет пользователям добавлять «обработчики событий» по типу сообщения, которые выполняются при поступлении сообщения. Это казалось гораздо менее раздутым, чем объявление события в Client классе для каждого конкретного Message . Аналогично, у меня также есть аннотация Command с несколькими конкретными реализациями. У них есть общедоступные конструкторы, обеспечивающие гибкость при взаимодействии с базовым протоколом.

Ответ №2:

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

Это действительно во многом зависит от природы разрабатываемого вами API и в некоторой степени от вкуса. Часто существует один основной класс или набор классов, к которым ваши пользователи будут обращаться большую часть времени, например, к NLog Logger , или AutoMapper Mapper , или NoRM Mongo , или фабрики классов в целом. Они должны быть в центре внимания и доступны для обнаружения, и вы могли бы привести веские доводы в пользу того, что лучше всего иметь это в вашем корневом пространстве имен.

Для других классов (тех, которые больше связаны с реализацией и меньше с API), очевидно, что вы хотите быть организованными, но вы можете играть довольно свободно и организовывать таким образом, который вам кажется естественным, при условии, что части API, которые пользователям нужно найти, наиболее заметны. Foo.Messages кажется, что это вполне разумный способ начать. С другой стороны, если 90% ваших классов являются Message подклассами, но существует важное различие между сообщениями сервера и сообщениями клиента, или фиолетовыми сообщениями и текстурными сообщениями, возможно, Foo.Server или Foo.Plaid являются подходящими типами пространств имен для вас.

Ответ №3:

Если вы создаете библиотеку и используете абстрактный класс Message со многими конкретными реализациями, часто может быть хорошей идеей скрыть все конкретные реализации от пользователя библиотеки и предоставить доступ к классу Factory, который вернет абстрактное сообщение (возвращаемый тип, фактический возвращаемый объект, конечно, будет конкретным), если это нормально для клиентов библиотеки, что часто бывает, он инкапсулирует 20 или даже больше классов и предоставляет доступ к требуемой функциональности отличным и удобным способом.