• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Projektowanie obiektowe - zwracanie wyniku walidacji.

Object Storage Arubacloud
0 głosów
441 wizyt
pytanie zadane 1 lipca 2018 w Java przez RafalS VIP (122,820 p.)

Cześć.

Problem: muszę napisać klasę walidator zgodną z zasadami SOLID. Walidacja może pójść źle z kilku powodów. Chciałbym poza booleanem isValid zwrócić powód niepowodzenia.

Czego już próbowałem:

  • zwracanie enuma ValidationFailureCause nie wchodzi w gre, bo enumy łamią zasade open-closed 
  • zwracanie klasy ValidationResult z polami boolean na każdy test prowadzi do stworzenia anemic domain model
  • uniknięcie anemicznego modelu przez wrzucenie walidacji do ValidationResult jakoś mi nie leży, bo walidacja przebiega na podstawie danych przesłanych do klasy i wtedy metoda validate klasy ValidationResult wygladalaby tak:
    public static ValidationResult validate(Input input, SomeExternalData data);
    

W tym momencie najbardziej przychylny jestem zwróceniu boolean'a oraz metodzie getLastFailureCause() zwracającej String z powodem niepowodzenia. Wtedy gdy walidacja sie nie powiedzie to zwracam się do walidatora o powod. 

Która z moich propozycji jest najbardziej czysta? A może powinien to rozwiązać w jeszcze inny sposób?

komentarz 1 lipca 2018 przez Aisekai Nałogowiec (42,190 p.)
Tak się zastanawiam, nie jestem pewien a chce też się dowiedzieć, czy rzucenie odpowiednim wyjątkiem łamie w jakiś sposób założenia solid/clean code? Teoretycznie można byłoby utworzyć Klase dziedziczaca po exception i rzucić nim jeśli jakaś zależność wystąpi.
komentarz 1 lipca 2018 przez RafalS VIP (122,820 p.)
Problem w tym, że niepoprawny input dla walidatora to chleb powszedni i nie jest to wyjątkowa sytuacja, a zatem nie możemy kontrolować normalnego przebiegu programu za pomocą wyjątków.

3 odpowiedzi

+1 głos
odpowiedź 1 lipca 2018 przez mbady Obywatel (1,280 p.)

Witaj, programuję w C# ale postaram się w pseudokodzie/opisie przedstawić ideę, jak będzie trzeba to mogę napisać kod w C#, a nawet w javie ale piszę z "marszu".

Nasuwa się pytanie pierwsze, czy chcesz wiedzieć dokładnie, która reguła zwróciła błąd czy tylko, że jest błąd i np.: w stringu opis wszystkich reguł które się nie powiodły ale to zawsze będziesz mógł sobie zmienić.

Moja propozycja jest następująca oczywiście, zawsze możesz zrobić te jako klasy generyczne, czyli w zależności od typu.

Powiedzmy, że masz konkretną klasę Validator (można oczywiście dodać interfejsy kwestia detali), która ma metody walidacyjne, detale potem wszystko też zależy jak chcesz tego używać ale postaram się przedstawić koncepcję.

Dodatkowo mamy klasę ValidationRule, która jest pojedynczą regułą i ma powiedzmy metodę bool IsValid oraz właściwość string ValidationError ale oczywiście można to delikatnie zmienić, żeby zwracała ValidationResult (która ma bool Is Valid oraz string z błędem, kwestia smaku).

Załóżmy, że chcesz zwalidować swój input używając trzech reguł więc tworzysz, trzy konkretne klasy ValidationRule i przekazujesz je jako lista do konstruktora Validator, a następnie w metodzie IsValid sprawdzasz wszystkie reguły i zwracasz odpowiedni rezultat, a dodatkowo inną metodą (np ValidationErrors) jeśli IsValid jest false zwracasz string lub listę stringów lub ValidationResult(s) jako listę (kwestia implementacji) i wiesz dokładnie który element z listy i dlaczego spowodował błąd walidacji.

Oczywiście konkretna implementacja będzie zależeć od wielu szczegółów tego co chcesz i jak zrobić ale wydaje mi się, że przedstawiłem ogólne podejście.

BTW: SOLID to tylko drogowskaz/definicja/reguły/pomoc :-) jak nie wiesz co zrobić to używasz SOLID i wtedy prawie zawsze powinno być ok, ale od każdej reguły można odejść o ile wie się dlaczego i co to powoduje (to gdzieś w necie znalazłem w podobnym brzmieniu).

+1 głos
odpowiedź 2 lipca 2018 przez Mateusz51 Nałogowiec (28,180 p.)
Najpopularniejszy framework spring rozwiązuje to w taki sposób że zwracany jest obiekt result który ma metody takie jak hasError, getAllErrors, getFieldError itd.

Dam Ci jeszcze jeden sposób do przemyślenia, w programowaniu funkcyjnym jest dość popularne użycie klasy Either która może przyjąć jedną z dwóch wartości. Przyjmuje się że jedna jest poprawna a druga reprezentuję błąd. Korzysta sie z niej wtedy gdy zwykły optional nie niesie wartości o przyczynach błędu.
+1 głos
odpowiedź 2 lipca 2018 przez mokrowski Mędrzec (156,220 p.)
Zwróć klasę implementującą interfejs ValidationResult która w zależności od tego czy wynik jest poprawny czy nie, rzuci wyjątkiem w trakcie pobrania zawartości tegoż wyniku. Jeśli nie chcesz obsługiwać tego wyjątkiem (a przecież będzie do obsłużenia lokalnie w kodzie pobrania wartości), to dodaj do klasy predykat isValid(). Na podstawie jego wartości (true/false), wykonasz operację obsługi.

W takiej obsłudze OCP nie łamiesz bo z łatwością wprowadzisz nową klasę bez zmiany istniejącego kodu a anemii domeny także nie będziesz miał bo zwracasz określony rezultat operacji. Ew. predykat także nie generuje problemu bo jest jeden i ściśle dotyczy klasy zwracanej.

Podobne pytania

0 głosów
2 odpowiedzi 321 wizyt
pytanie zadane 23 września 2023 w C# przez sisOOO Obywatel (1,370 p.)
0 głosów
1 odpowiedź 127 wizyt
0 głosów
0 odpowiedzi 319 wizyt
pytanie zadane 4 czerwca 2018 w Java przez Artur313 Użytkownik (790 p.)

92,757 zapytań

141,679 odpowiedzi

320,437 komentarzy

62,101 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...