Kilka miesięcy temu spod krzywej ręki mojej wydostał się post o “klasach i metodach częściowych” (“Partial classes & partial methods – explained”). Wniosek z niego można było wysnuć jeden: trzymaj się z dala od tych mechanizmów, jeśli nie generujesz kodu. Muszę jednak przyznać, że ostatnio natknąłem się na kolejny scenariusz, gdzie klasy częściowe są… przydatne.
Weźmy za przykład standardową aplikację www. Zdarza się, że strony przekazują pomiędzy sobą parametry w query stringu. W takich przypadkach wygodnie jest mieć jedno centralne miejsce, w którym przechowujemy wszystkie wykorzystywane klucze. Może ono wyglądać tak:
1: public static class QueryStringKeys 2: { 3: public const string UserId = "userId"; 4: public const string PostId = "postId"; 5: public const string SortDirection = "sorting"; 6: }
Łatwo domyślić się, że gdy liczba takich kluczy urośnie, to klasa stanie się bezsensownym zgromadziskiem niepowiązanych ze sobą napisów. Najsensowniej jest chyba podzielić klucze na logiczne grupy i zebrać w dedykowanych klasach: klucz reprezentujący id użytkownika i datę jego urodzenia wstawimy do Users, wszystko co związane z blogami: do Blogs itd (celowo nie używam określeń “moduł” czy “aggregate root”, żeby nie mieszać pojęć). Jak zatem nasz prosty przykład wyglądałby po takiej zmianie?:
1: public static class QueryStringKeys 2: { 3: public const string SortDirection = "sorting"; 4: 5: public static class Users 6: { 7: public const string UserId = "userId"; 8: public const string BirthDate = "birth"; 9: } 10: 11: public static class Blogs 12: { 13: public const string PostId = "postId"; 14: } 15: }
Okej, mamy to wszystko pogrupowane, ale… czytelność kodu wcale się nie poprawiła – wręcz odwrotnie! I tutaj do gry wchodzą partial classes… Najwygodniejszym sposobem, jaki udało mi się wymyślić, jest utworzenie głównej klasy QueryStringKeys zawierającej klucze wspólne dla wszystkich grup oraz ewentualnie metody pomocnicze. Każdą klasę zagnieżdżoną (wiem, łamię kolejną zasadę – “nie używaj typów zagnieżdżonych” – ale robię to świadomie i… tak jest bardzo wygodnie) wrzucamy do osobnego pliku:
[QueryStringKeys.cs]
1: public static partial class QueryStringKeys 2: { 3: public const string Id = "id"; 4: public const string SortDirection = "sorting"; 5: 6: public static string Create(string key, string value) 7: { 8: return key + "=" + value; 9: } 10: }
[UserQueryStringKeys.cs]
1: public static partial class QueryStringKeys 2: { 3: public static class Users 4: { 5: public const string UserId = "userId"; 6: public const string BirthDate = "birth"; 7: } 8: }
[BlogQueryStringKeys.cs]
1: public static partial class QueryStringKeys 2: { 3: public static class Blogs 4: { 5: public const string PostId = "postId"; 6: } 7: }
Mało tego – żeby nie zaśmiecać SolutionExplorer (eksploratora solucji?:) ) zastosujemy jeszcze jeden trick, o którym kiedyś dawno temu pisałem (“Zwijanie” plików w Visual Studio). W VS wygląda to tak:
Wpadł ktoś może na lepsze rozwiązanie tej kwestii?