Buduję biblioteki z różnymi małymi funkcjami narzędziowymi w języku C # i próbuję zdecydować o przestrzeni nazw i konwencji nazewnictwa klas. Moja obecna organizacja wygląda następująco:
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 {...}
Czy to dobry sposób na uporządkowanie przestrzeni nazw i klas, czy jest lepszy sposób? W szczególności wydaje się, że posiadanie tej samej nazwy w przestrzeni nazw i nazwie klasy (np. Company.TextUtils
Przestrzeni nazw i TextUtils
klasy) jest po prostu duplikacją i sugeruje, że schemat mógłby być lepszy.
SISuffix
zamiastSISuffixes
) i myślę, że liczba pojedyncza brzmi lepiej.Suffix.A
brzmi „sufiks A”. Ponadto generalnie unikam powtarzania nazw z poziomu w hierarchii. To znaczy zamiastCompany.SIUnits.SISuffixes
pochylać sięCompany.SI.Suffix
iCompany.SI.Unit
Odpowiedzi:
Bardzo trudno jest ustalić, jak skuteczna jest twoja strategia nazewnictwa w oderwaniu od reszty kodu.
Przestrzeń nazw powinna dać pojęcie, gdzie mieści się w szerokiej strukturze bazy kodu, a nazwa klasy zwykle opisuje, jaką funkcjonalność lub pojęcie reprezentuje w tym obszarze.
Odkładając na bok zastrzeżenia, w twoim konkretnym przykładzie, jeśli prawdopodobnie masz o wiele więcej klas typu „Util”, rozważę umieszczenie ich pod
Company.Utils.Maths
itd. W ten sposób, jeśli chcesz dodać funkcjonalność wspólną dla wielu obszarów narzędziowych, masz już naturalna lokalizacja dla tego.źródło
Jest fajny dokument, który zawiera wiele reguł, których należy przestrzegać, aby zachować zgodność z Microsoft: Framework Design Guidelines .
Jedną rzecz, którą powinieneś zmienić: nie nazywaj klas jako ich przestrzeni nazw. Doprowadzi to do pomyłek kompilatora. Po prostu nie. Znajdź lepszą nazwę dla klasy przestrzeni nazw.
źródło
Minęło trochę czasu, odkąd pracowałem z C # lub ekosystemem .NET, więc nie mogę powiedzieć, jakie są obecnie zalecane najlepsze praktyki. Polecam zmianę twoich nazwisk w ten sposób:
To, co zrobiłem tutaj, to usunięcie „Utils” z nazw przestrzeni nazw. Myślę, że „Util” nie powinno znajdować się w przestrzeni nazw, ponieważ
Company.Text
przestrzeń nazw może kiedyś zawierać klasy, które nie są klasami tekstowymi. PrzestrzeńCompany.Math
nazw już zawiera,ArbitraryPrecisionNumber
co nie wydaje się „narzędziem”.Usunięcie „Util” z przestrzeni nazw usuwa również wszelkie nieporozumienia, które mogą wyniknąć z posiadania dwóch rzeczy o tej samej nazwie (jak wspomniano w odpowiedzi Roberta: /software//a/340440/13156 )
Innym sposobem na zorganizowanie kodu:
W takim przypadku wszystkie klasy narzędzi znajdują się w tej samej przestrzeni nazw. Nie ma więcej
Company.Text
nazw, ponieważ jedyną rzeczą, nie było klasy narzędzie.Osobiście uważam, że pierwsza opcja jest nieco bardziej przejrzysta.
źródło
Użycie tej samej nazwy dla przestrzeni nazw i klasy w niej jest problematyczne.
Jeśli przestrzeń nazw zawiera więcej niż jedną klasę, dlaczego umieszczane są tam inne klasy? to nie wydaje się właściwe, ponieważ celem nazwy przestrzeni nazw jest opisanie wszystkich klas w niej zawartych , a nie tylko jednej. Na przykład, jeśli masz
JsonSerialization
,BinarySerialization
iXmlSerialization
klas w przestrzeni nazw, warto byłoby, aby wymienić swoje nazwXmlSerialization
?Zwykle dzieje się tak, że z powodu wyodrębnienia klasy z istniejącej przestrzeni nazw lub połączenia wielu klas lub innej reorganizacji, znajdujesz się w przestrzeni nazw zawierającej główną klasę; stopniowo wprowadzane są tam mniejsze klasy, ponieważ są one nieco związane z klasą pierwotną. Na przykład przestrzeń nazw
LogParser
może zawierać jedną klasęLogParser
, a następnie ktoś ją umieszczaLogConverter
, ponieważ jest to dość związane z analizatorem składniLogSearcher
, itd. Problem polega na tym, że nazwa przestrzeni nazw nie została zmieniona: jak tylkoLogConverter
została dodana, właściwość nazwa powinna zostać zmieniona naLogsProcessing
lub po prostuLogs
.Jeśli przestrzeń nazw zawiera tylko jedną klasę, może to oznaczać problem w organizacji kodu.
Chociaż kilkakrotnie widziałem sytuacje, w których jedna klasa z właściwymi zasadami SOLID bardzo różniła się od wszystkiego innego w bazie kodu i dlatego została umieszczona w dedykowanej przestrzeni nazw, takie przypadki są rzadkie. Częściej oznacza to problem. Podobnie nic nie stoi na przeszkodzie, aby klasa zawierała jedną metodę, ale najczęściej klasy takie wskazywałyby na problem.
Nawet jeśli twoja przestrzeń nazw zawiera tylko jedną klasę, zwykle istnieje sposób, aby być bardziej szczegółowym przy nazywaniu klasy i bardziej ogólnym przy nazywaniu przestrzeni nazw. Wyobraź sobie aplikację, która między innymi powinna w danym momencie konwertować pliki zapisane w formacie ABC do formatu DEF. Konwersja nie wymaga żadnej deserializacji / serializacji do / z obiektów biznesowych i odbywa się poprzez zastosowanie zestawu wyrażeń regularnych, które są wystarczająco krótkie, aby można je było umieścić w samej klasie konwersji o nazwie
AbcToDefConverter
. Cała logika konwersji zajmuje około 80 LLOC w około dziesięciu współzależnych metodach - wydaje się być sytuacją, w której absolutnie nie ma potrzeby dzielenia istniejącej klasy ani tworzenia dodatkowych klas. Ponieważ pozostała część aplikacji nie ma nic wspólnego z konwersjami, klasy nie można grupować z innymi klasami w istniejących przestrzeniach nazw. Więc tworzy się przestrzeń nazwanąAbcToDefConverter
. Chociaż nie ma w tym nic złego, można również użyć bardziej ogólnej nazwy, takiej jakConverters
. W językach takich jak Python, w których preferowane są krótsze nazwy i narzucane jest powtarzanie, może się nawet zdarzyćconverters.Abc_To_Def
.Dlatego używaj innych nazw dla przestrzeni nazw niż dla klas, które zawierają. Nazwa klasy powinna wskazywać, co robi klasa, a nazwa przestrzeni nazw powinna podkreślać to, co wspólne dla wszystkich klas w niej zawartych.
Nawiasem mówiąc, klasy użytkowe są z natury złe: zamiast zawierać coś konkretnego, na przykład arytmetykę dowolnej precyzji, raczej zawierają wszystko, co nie znalazło się w innych klasach . To po prostu złe nazewnictwo, podobnie jak
Miscellaneous
katalog na pulpicie - coś, co wskazuje na brak organizacji.Nazywanie istnieje z jakiegoś powodu: aby ułatwić Ci życie, gdy będziesz musiał później znaleźć rzeczy. Wiesz, że jeśli musisz narysować wykres, możesz spróbować wyszukać „wykres” lub „wykres”. Gdy musisz zmienić sposób generowania faktur przez aplikację, wyszukaj „faktura [e / ing]” lub „rachunek”. Podobnie, spróbuj wyobrazić sobie przypadek, w którym powiesz sobie: „hm, ta funkcja prawdopodobnie powinna być znaleziona w misc”. Nie mogę
Spójrz na .NET Framework. Czy większość z tych klas nie jest klasami użytkowymi? Mam na myśli, że mają niewiele wspólnego z domeną biznesu. Jeśli pracuję nad aplikacją finansową, witryną e-commerce lub platformą edukacyjną nowej generacji, serializowanie XML, czytanie plików lub wykonywanie zapytań SQL lub wykonywanie transakcji to wszystko, co jest użytecznością. Jednak nie są one wywoływane
UtilitySerialization
lubUtilityTransaction
nie są wUtility
przestrzeni nazw. Mają odpowiednie nazwy, które umożliwiają (i ułatwiają, dzięki deweloperom .NET!) Znajdowanie ich, kiedy ich potrzebuję.To samo przychodzi do swoich klas ty powszechnie ponownego użycia w swoich aplikacjach. Nie są to klasy użytkowe. Są to klasy, które robią pewne rzeczy, a rzeczy, które robią, powinny być nazwami klas.
Wyobraź sobie, że stworzyłeś kod, który zajmuje się jednostkami i konwersją jednostek. Możesz nazwać to
Utility
i być znienawidzonym przez swoich kolegów; lub możesz to nazwaćUnits
iUnitsConversion
.źródło
Math
? Nie rozumiem, jak dodanieUtility
sufiksu do wszystkiego ułatwiłoby nam życie. Czy podczas korzystania zSystem.Math.Min()
metody .NET wolisz pisaćSystemUtility.MathUtility.Min()
? We wszystkich przypadkach mocno zredagowałem swoją odpowiedź, więc powinna być teraz jaśniejsza.