Najbezpieczniej i "koszernie" - choć kosztem sporej ilości kodu, w każdym razie w Javie - można to zrobić zaprzęgając do tego system typów.
Czyli można zrobić walidator (teoretycznie mógłby być "wciągnięty" do fabryki i nie stanowić osobnej klasy, jeśli chcemy iść na skróty):
public class PeselValidator {
public boolean isValid(String pesel) {
return pesel.length() == 11; // plus inne weryfikacje właściwe dla PESEL-u, np. cyfry kontrolnej itp.
}
}
A fabryka:
public final class PeselFactory {
private final PeselValidator validator;
public PeselFactory(PeselValidator validator) {
this.validator = validator;
}
abstract class Pesel {
final String value;
public Pesel(String value) {
this.value = value;
}
}
final class ValidPesel extends Pesel {
private ValidPesel(String value) {
super(value);
}
}
final class InvalidPesel extends Pesel {
private InvalidPesel(String value) {
super(value);
}
}
public Pesel createPesel(String pesel) {
return validator.isValid(pesel)
? new ValidPesel(pesel)
: new InvalidPesel(pesel);
}
}
Czyli, w duchu programowania funkcyjnego, prawidłowa wartość PESEL staje się konkretnym typem, ValidPesel
. (W Kotlinie można by to zaimplementować bardziej elegancko dzięki sealed classes
).
Ponieważ klasa ta ma prywatny konstruktor, nie jesteś w stanie stworzyć jej inaczej niż poza tą fabryką, czyli nie ma jak obejść walidatora.
Od tej pory klasa Person
(czy tam Osoba
) nie przyjmuje wartości PESEL w formie prymitywnego typu String, ale ValidPesel pesel
.
Dzięki temu, z uwagi na powyższe, fizycznie nie da się do niej przekazać nieprawidłowego PESELu. Nie blokujemy tego wyjątkiem (który działa dopiero w czasie uruchomienia), ale na poziomie silnika typów, czyli już na etapie kompilacji.
Zaletą jest ściągnięcie walidacji z poziomu Osoby do PESEL-u, który staje się pełnoprawnym obiektem. Ma to spory plus: bo niby dlaczego to Osoba ma wiedzieć, co to jest prawidłowy PESEL?
Jeśli pojawi się potrzeba walidacji innych danych, np. NIP-u albo daty urodzenia, również zamkniemy tę logikę w osobnych typach. Dzięki temu unikniemy pakowania w kod zajmujący się Osobami ogólnie - wiedzy na temat różnych szczegółów biurokratycznych.
A PESEL można odtąd walidować (i testować tę walidację) także poza kontekstem Osoby.