Czy dobrą praktyką jest zastępowanie stałych używanych poza klasami przez metody pobierające?
Na przykład, czy lepiej jest użyć if User.getRole().getCode() == Role.CODE_ADMIN
lub if User.getRole().isCodeAdmin()
?
Doprowadziłoby to do tej klasy:
class Role {
constant CODE_ADMIN = "admin"
constant CODE_USER = "user"
private code
getRoleCode() {
return Role.code
}
isCodeAdmin () {
return Role.code == Role.CODE_ADMIN
}
isCodeUser () {
return Role.code == Role.CODE_USER
}
}
object-oriented
iść do
źródło
źródło
User.HasRole(Role.Admin)
.User.getRole().getCode()
jest to już nieprzyjemna lektura, porównanie Kodeksu z rolą czyni go jeszcze bardziej niezręcznym.Odpowiedzi:
Po pierwsze, należy pamiętać, że robienie czegoś takiego
entity.underlyingEntity.underlyingEntity.method()
jest uważane za zapach kodu zgodnie z prawem Demetera . W ten sposób ujawniasz wiele szczegółów implementacji konsumentowi. I każda potrzeba rozszerzenia lub modyfikacji takiego systemu będzie bardzo boleć.Biorąc to pod uwagę, zaleciłbym, abyś miał metodę
HasRole
lub zgodnie z komentarzem CodesInChaos. W ten sposób sposób, w jaki role są wdrażane na użytkowniku, pozostaje szczegółem implementacji dla konsumenta. Bardziej naturalne wydaje się także pytanie użytkownika o jego rolę zamiast pytania o szczegóły jego roli, a następnie podjęcie decyzji w oparciu o to.IsAdmin
User
Unikaj także używania
string
s, chyba że jest to konieczne.name
jest dobrym przykłademstring
zmiennej, ponieważ zawartość nie jest wcześniej znana. Z drugiej strony,role
jeśli masz dwie wyraźne wartości, które są dobrze znane w czasie kompilacji, lepiej użyj silnego pisania. Właśnie wtedy wchodzi w grę typ wyliczenia ...Porównać
z
Drugi przypadek daje mi o wiele więcej informacji na temat tego, co powinienem przekazywać. Zapobiega mi również błędnym przekazaniem nieważnego
string
na wypadek, gdybym nie miał pojęcia o twoich stałych ról.Następnie jest decyzja, jak będzie wyglądać rola. Możesz użyć enum bezpośrednio zapisanego na użytkowniku:
Z drugiej strony, jeśli chcesz, aby twoja rola zachowywała się sama, zdecydowanie powinna ukryć szczegóły dotyczące sposobu decydowania o jej typie:
Jest to jednak dość gadatliwe i złożoność wzrasta z każdym dodaniem roli - zwykle tak kończy się kod, gdy próbujesz w pełni przestrzegać prawa Demetera. Powinieneś ulepszyć projekt, w oparciu o konkretne wymagania modelowanego systemu.
Zgodnie z twoim pytaniem, myślę, że lepiej wybrać pierwszą opcję z enum bezpośrednio
User
. Jeśli potrzebujesz więcej logikiRole
, drugą opcję należy uznać za punkt wyjścia.źródło
X
z pewnością pozwoli ci tworzyć ciągi wywołań funkcji, takich jakX.foo().bar().fee()...
. W tym płynnym interfejsie foo, bar i opłata będą funkcjami wewnątrz klasyX
zwracającymi obiekt typuX
. Ale w przypadku „instance.property.property.method () wspomnianego w tym przykładzie dwaproperty
wywołania byłyby w rzeczywistości w osobnych klasach. Problem polega na tym, że przechodzisz przez kilka warstw abstrakcji, aby zdobyć szczegóły niskiego poziomu.instance.property.property.method()
niekoniecznie stanowi naruszenie, a nawet zapach kodu; zależy to od tego, czy pracujesz z obiektami czy strukturami danych.Node.Parent.RightChild.Remove()
prawdopodobnie nie stanowi naruszenia LoD (choć śmierdzi śmiercią z innych powodów).var role = User.Role; var roleCode = role.Code; var isAdmin = roleCode == ADMIN;
jest prawie na pewno naruszeniem, mimo że zawsze „użyłem tylko jednej kropki”.instance.property.property.method()
jest to naruszenie LoD, ale OP ma,instance.method().method()
co powinno być w porządku. W twoim ostatnim przykładzie jest tyle kodu,User
który służy tylko jako fasada dlaRole
.Wydaje się głupio mieć funkcję sprawdzającą, czy przechowywany kod to kod administratora. Naprawdę chcesz wiedzieć, czy ta osoba jest administratorem. Więc jeśli nie chcesz ujawniać stałych, nie powinieneś również ujawniać, że istnieje kod, a wywołaj metody isAdmin () i isUser ().
To powiedziawszy, „jeśli User.getRole (). GetCode () == Role.CODE_ADMIN” naprawdę jest garstką tylko do sprawdzania, czy użytkownik jest administratorem. Ile rzeczy musi pamiętać deweloper, żeby napisać ten wiersz? Musi pamiętać, że użytkownik ma rolę, rola ma kod, a klasa roli ma stałe dla kodów. To dużo informacji, które dotyczą wyłącznie implementacji.
źródło
Oprócz tego, co już napisali inni, należy pamiętać, że użycie stałej ma jeszcze jedną wadę: jeśli coś zmieni sposób, w jaki obchodzisz się z prawami użytkownika, wszystkie te miejsca również muszą zostać zmienione.
A to utrudnia ulepszanie. Może chciałbyś kiedyś mieć superużytkownika , który oczywiście ma również uprawnienia administratora. Dzięki enkapsulacji jest to w zasadzie jedno-liniowy dodatek.
Jest nie tylko krótki i czysty, ale także łatwy w użyciu i zrozumiały. I - może przede wszystkim - trudno się pomylić.
źródło
Chociaż w dużej mierze zgadzam się z sugestiami, aby unikać stałych i mieć metodę
isFoo()
itp., Jeden możliwy kontrprzykład.Jeśli istnieją setki tych stałych, a wywołania są mało używane, napisanie setek metod isConstant1, isConstant2 może nie być warte wysiłku. W tym szczególnym przypadku użycie stałych jest uzasadnione.
Zauważ, że używanie wyliczeń lub
hasRole()
pozwala uniknąć potrzeby pisania setek metod, więc jest to najlepszy ze wszystkich możliwych na świecie.źródło
Nie sądzę, aby którakolwiek z przedstawionych opcji była zasadniczo błędna.
Widzę, że nie zasugerowałeś jednej rzeczy, którą nazwałbym całkowicie błędną: twardego kodowania kodów ról w funkcjach spoza klasy Role. To jest:
Powiedziałbym, że zdecydowanie się myli. Widziałem programy, które to robią, a następnie otrzymują tajemnicze błędy, ponieważ ktoś źle napisał ciąg. Pamiętam, jak kiedyś programista napisał „zapas”, gdy funkcja sprawdzała „zapas”.
Gdyby było 100 różnych ról, bardzo niechętnie pisałbym 100 funkcji, by sprawdzić każdą możliwą. Prawdopodobnie utworzyłbyś je, pisząc pierwszą funkcję, a następnie kopiując i wklejając ją 99 razy, i ile chcesz postawić na to, że w jednym z tych 99 egzemplarzy zapomnisz zaktualizować test lub dostaniesz się, gdy przejrzałeś listę, więc teraz masz
Osobiście unikałbym również łańcuchów połączeń. Wolałbym pisać
następnie
i w tym momencie dlaczego piszą:
Następnie powiadom klasę użytkownika, jak sprawdzić rolę.
źródło