C # простір імен та назви класів для бібліотек


26

Я будую бібліотеки з різними невеликими функціями утиліти в C # і намагаюся визначитися з простором імен та умовами іменування класів. Моя поточна організація така:

Company
Company.TextUtils
    public class TextUtils {...}
Company.MathsUtils
    public class MathsUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SIUnits
    public enum SISuffixes {...}
    public class SIUnits {...}

Це хороший спосіб впорядкувати простір імен та класи, чи є кращий спосіб? Зокрема, здається, що однакове ім’я у просторі імен та імені класу (наприклад, Company.TextUtilsпростір імен та TextUtilsклас) - це просто дублювання, що дозволяє припустити, що схема може бути кращою.



5
Настанови Майкрософт рекомендують назви для однини (тому SISuffixзамість них SISuffixes) поодинокі назви , і я думаю, що однина читає краще. Suffix.A читається як "суфікс А". Крім того, я взагалі уникаю повторення імен з рівня вгору в ієрархії. Тобто, замість того Company.SIUnits.SISuffixes, я схиляюся до Company.SI.SuffixіCompany.SI.Unit
Харрісон Paine

Відповіді:


9

Дуже важко визначити, наскільки ефективна ваша стратегія іменування у відриві від решти коду.

Простір імен повинен дати деяке уявлення про те, де воно вписується в широку структуру вашої кодової бази, а назва класу зазвичай описує, який функціонал або поняття він представляє в цій області.

Застереження у вашому конкретному прикладі, якщо ви, ймовірно, матимете набагато більше класів типу «Util», я б розглядав можливість їх розміщення Company.Utils.Mathsі т. Д. Таким чином, якщо вам потрібно додати функціональність, спільну для кількох областей, у вас уже є природне місце для цього.


1
Це звучить як гарна ідея. Перестаньте хвилюватися занадто сильно, просто занесіть все до "Company.Util".
користувач

30

Є чудовий документ, який містить безліч правил, яких слід дотримуватися, щоб відповідати Microsoft: Framework Design Guidelines .

Одне, що вам слід змінити: Не називайте класи їх простором імен. Це призведе до компіляції компіляторів. Просто ні. Знайдіть кращу назву для класу простору імен.


3
Пряме посилання на вказівки щодо простору імен: msdn.microsoft.com/en-us/library/ms229026(v=vs.110).aspx
Паготті

1
Що за збігом обставин чи ні - це те саме ім'я чудової книги на цю тему, яку також написали люди Microsoft, які брали участь у створенні рамки DotNet, з кількома зауваженнями про те, що вони зробили правильно, і де вони помилилися. Варто прочитати: amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/…
Мачадо

@nvoigt, чи можете ви відредагуйте свою відповідь, щоб додати цитату за посиланням нашого друга Паготті: " НЕ використовуйте те саме ім'я для простору імен та типу в цьому просторі імен. Наприклад, не використовуйте налагодження як ім'я простору імен і тоді також надайте клас під назвою Debug в одній просторі імен. Кілька компіляторів вимагають, щоб такі типи були повністю кваліфіковані. "
Мачадо

2
Caveat: Іноді Назва продукту краще, ніж використовувати назву компанії. Був у кількох сценаріях, коли компанія була викуплена, і нам довелося створювати нові простори імен по всій платі та перевипускати. Я думаю, це дуже незначно, але я хотів це зазначити.
Джон Рейнор

1
Настанови Microsoft щодо дизайну рамок дуже сумнівні, містять помилкові твердження про те, як працює .NET, і дуже часто Microsoft не дотримується їх. Їх вказівки щодо іменування є хорошими, але я б уникав пов'язувати загальні вказівки із твердженням, що "слід дотримуватися їх".
Карл Лет

6

Минув час, коли я працював із екосистемою C # або .NET, тому я не можу сказати, якими є поточні рекомендовані найкращі практики. Я рекомендую змінити свої імена на зразок цього:

Company
Company.Text
    public class TextUtils {...}
Company.Math
    public class MathUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

Що я тут зробив, це видалити "Utils" з імен простору імен. Я думаю, що "Util" не повинен знаходитися в просторі імен, тому що в Company.Textпросторі імен одного дня можуть бути класи, які не є текстовими класами. Company.MathІмен уже містить ArbitraryPrecisionNumberякі не схоже , щоб бути «утиліта».

Видалення "Util" з простору імен також очищує будь-яку плутанину, яка може виникнути, якщо дві речі мають однакове ім'я (про що йдеться у відповіді Роберта: /software//a/340440/13156 )

Ще один спосіб ви могли організувати код:

Company
Company.Util
    public class TextUtils {...}
    public class MathUtils {...}
Company.Math
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

У цьому випадку всі класи утиліти знаходяться в одному просторі імен. Більше Company.Textпростору імен більше немає, оскільки єдиним, у чому був клас корисності.

Особисто я вважаю перший варіант трохи більш зрозумілим.


4

Використовувати те саме ім’я для простору імен та класу всередині нього проблематично.

  • Якщо простір імен містить більше одного класу, чому б там розміщувати інші класи? це не вірно, тому що метою назви простору імен є опис усіх класів всередині нього, а не лише одного. Наприклад, якщо у вас є JsonSerialization, BinarySerializationі XmlSerializationкласи в просторі імен, чи буде сенс називати простір імен XmlSerialization?

    Зазвичай відбувається те, що через вилучення класу з існуючого простору імен або злиття між декількома класами чи іншою реорганізацією ви опиняєтесь з простором імен, що містить основний клас; прогресивно, мінорні класи ставляться туди, оскільки вони трохи пов'язані з початковим класом. Наприклад, простір імен LogParserможе містити один клас LogParser, а потім хтось ставить LogConverter, тому що він досить пов'язаний з аналізатором, то LogSearcherі т. Д. Проблема тут полягає в тому, що ім’я простору імен не було змінено: як тільки LogConverterбуло додано, ім'я повинно бути змінено LogsProcessingабо просто Logs.

  • Якщо простір імен містить лише один клас, це може бути ознакою проблеми в кодовій організації.

    Хоча я не раз бачив ситуації, коли один клас із належними принципами SOLID сильно відрізнявся від будь-якого іншого в кодовій базі і тому був розміщений у виділеному просторі імен, такі випадки рідкісні. Частіше це вказує на проблему. Так само ніщо не заважає вам мати клас, що містить єдиний метод, але частіше за все такі класи вказували б на проблему.

    Навіть якщо у вашому просторі імен є лише один клас, зазвичай існує спосіб бути більш конкретним при іменуванні класу, і більш загальним при називанні простору імен. Уявіть програму, яка, крім іншого, повинна в даний момент перетворити файли, записані у форматі ABC, у формат DEF. Перетворення не вимагає будь-якої десеріалізації / серіалізації в / з бізнес-об'єктів, і це здійснюється за допомогою набору регулярних виразів, які досить короткі, щоб бути поміщеними в сам клас перетворення, який називаєтьсяAbcToDefConverter. Вся логіка перетворення займає близько 80 LLOC приблизно в десяти взаємозалежних методах - схоже на ситуацію, коли абсолютно не потрібно ні розбивати існуючий клас, ні створювати додаткові класи. Оскільки решта частини програми не має нічого спільного з перетвореннями, клас не може бути згрупований з іншими класами у існуючих просторах імен. Отже, створюється простір імен під назвою AbcToDefConverter. Хоча в цьому немає нічого поганого, можна також використовувати більш загальну назву, наприклад Converters. У таких мовах, як Python, де кращі назви кращі і повторення перекинуто, це може навіть стати converters.Abc_To_Def.

Тому використовуйте інші імена для просторів імен, ніж для класів, які вони містять. Ім'я класу повинно вказувати на те, що робить клас, а ім’я простору імен повинно підкреслювати те, що є загальним у всіх класах, що входять до нього.


До речі, корисні класи помилкові за своєю природою: замість того, щоб містити щось конкретне, наприклад, арифметику довільної точності, вони швидше містять усе, що не знайшло свого шляху в інших класах . Це просто погана назва, як Miscellaneousкаталог на робочому столі, що свідчить про недостатню організацію.

Іменування існує з причини: щоб полегшити ваше життя, коли вам потрібно знайти речі пізніше. Ви знаєте, що якщо вам потрібно намалювати діаграму, ви можете спробувати знайти "діаграму" або "сюжет". Коли вам потрібно змінити спосіб отримання додатком рахунків-фактур, ви шукаєте "рахунок-фактуру" або "рахунок". Аналогічно, спробуйте уявити собі випадок, коли ви скажете собі: "Гм, ця функція, мабуть, має бути знайдена в різному". Я не можу.

Подивіться на .NET Framework. Чи не більшість з цих класів корисних програм? Я маю на увазі, у них мало спільного з діловим бізнесом. Якщо я працюю над фінансовим додатком, веб-сайтом електронної комерції чи наступною платформою для навчання ген, серіалізація XML чи читання файлів або виконання запитів SQL або здійснення транзакцій - це все корисне. Однак вони не називаються UtilitySerializationабо UtilityTransaction, і їх немає в Utilityпросторі імен. Вони мають власні імена, завдяки чому можна (і, дякую розробникам .NET!) Знайти їх, коли мені це потрібно.

Те ж саме йде для ваших класів , які ви зазвичай повторно використовувати в своїх додатках. Вони не є корисними класами. Це класи, які роблять певні речі, і те, що вони роблять, насправді має бути назвами класів.

Уявіть, що ви створили якийсь код, який стосується одиниць та перетворення одиниць. Ви можете назвати це Utilityі ненавидіти колеги; або ви можете назвати це Unitsі UnitsConversion.


7
"Корисні класи неправильні за своєю природою". Цікаво. Яке рішення ви пропонуєте для чогось такого типу, як утиліта класу функцій Math? Чи повинен екземпляр об'єкта Math дійсно необхідний для використання функцій, що перевищують основні арифметичні оператори?
FrustratedWithFormsDesigner

1
Я згоден з вами, але що ви пропонуєте як альтернативу?
користувач


4
Я затягував із створенням бібліотеки "утиліти" на найдовший час, але зрештою вам просто доведеться поступитися. Альтернативою є наявність DLL-файлів, що складаються приблизно з 3 рядків коду, що просто громіздко (і нагадує мені про безлад залежностей node.js: ), або копіювати та вставляти ваші корисні методи до кожного класу, який може їм знадобитися (щоб уникнути наявності цього класу "колекція випадкових методів"). ІМО врешті-решт це необхідне зло.
Матті Віркюнен

3
@FrustratedWithFormsDesigner: просто ... Math? Я не бачу, як додавання Utilityсуфікса до всього полегшило б наше життя. Використовуючи System.Math.Min()метод .NET , чи дійсно ви віддаєте перевагу SystemUtility.MathUtility.Min()замість цього писати ? У всіх випадках я сильно відредагував свою відповідь, тому зараз має бути зрозуміліше.
Арсеній Муренко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.