Walidowanie

0

Uogólniając jak najlepiej walidować przed użyciem metody?


class Service {
    this validate(Object o) {
        isValid = isOk(o);
        if ( !isValid) {
            throw new Exception();
            log.error("rerer");
        }
       return this;
    }

    void run(Object o) {
        o.run();
    }
}

// CLIENT:
service.validate(o).run(o);

czy


class Service {
// przez buildera, który interfejsami najpierw pozwala puscic tylko validatei dopiero run, nie chce mi się pisać tego
}

// CLIENT:
service.validate(o).run();

czy


class Service {
    void validate(Object o) {
        isValid = isOk(o);
        if ( !isValid) {
            throw new Exception();
            log.error("rerer");
        }
       return this;
    }

    void runSafe(Object o) {
        validate(o);
        o.run();
    }
}

// CLIENT:
service.runSafe(o);

czy


class Service {
    boolean isValid(Object o) {
        return isOk(o);
    }

    void run(Object o) {
        o.run();
    }
}

// CLIENT:
isValid = service.validate(o)
if (isValid) {service.runSafe();}
else {}

czy


class Service {
    Service.ValidationResult isValid(Object o) {
        boolean isValid isOk(o);
        return new ValidationResult(o, isValid);
    }

    void run(ValidationResult vr) {
        vr.o.run();
    }
}

// CLIENT:
ValidationResult vr = service.validate(o)
service.run(vr)

Inaczej?

1

Są różne typy walidacji. Strukturę/typy waliduje się wcześniej (np. przed odpaleniem metody kontrolera), null/nienull wolę też przed metodą, żeby nie robić miliona null checkow w środku, natomiast reguły biznesowe i ich spójność wewnątrz metody ze względu na kohezje.

2

Według mnie dobrze jest mieć osobny Validator z metodą validate - tutaj od razu trzeba wybrać czy taka metoda zwraca true/false (wtedy bardziej odpowiednią nazwą byłoby isValid) czy jest void i rzuca wyjątkiem w razie errorów. Można też wyekstraktować interfejs do tego i mieć kilka różnych walidatorów. Wtedy service by miał zależność do interfejsu Validator<T> i wykonywał validator.validate(..) przed wykonaniem swojej logiki. Wtedy można mu wstrzyknąć różne implementacje walidatorów.

3

Walidacja fizyczna poprawności danych (puste wartości, nulle): przed wejściem do metody
Walidacja logiczna poprawności danych: wewnątrz metody/serwisu, najwygodniej wydzielić gdzieś do jakiegoś XValidator, przy skomplikowanych regułach można przetestować łatwiej jednostkowo

0

@Julian_:

Ale jak odpalasz ten validator kiedy ktora opcja?

W przypadku wybrania walidatora z void i rzucania wyjątku w przypadku errora:

class MyService {

  private Validator<String> validator;

  MyService(Validator<String> validator) {
    this.validator = validator;
  }

  void doSomething(String input) {
     validator.validate(input);
     // rest of the service logic
  }

}
2

Na kiego grzyba doSth bierze ValidationResult, skoro i tak wywołujesz po isValid¿

0
jarekr000000 napisał(a):

Na kiego grzyba doSth bierze ValidationResult, skoro i tak wywołujesz po isValid¿

żeby wymusić na użytkowniku robienie walidacji, a przy okazji dać mu wynik walidacji, by se obsłużył jak chce.

2

@Julian_: Skąd pomysł, żeby do serwisu wpuszczać byle co? Czy nie lepiej stworzyć Value Objecta, z metodą statyczną (lub metodami) tworzącą tylko prawilne obiekty, a metoda run serwisu akceptuje obiekty tylko tej klasy.

0
cs napisał(a):

@Julian_: Skąd pomysł, żeby do serwisu wpuszczać byle co? Czy nie lepiej stworzyć Value Objecta, z metodą statyczną (lub metodami) tworzącą tylko prawilne obiekty, a metoda run serwisu akceptuje obiekty tylko tej klasy.

Chodzi o Object w metodzie doSth? Nie chciało mi się wymyślać nic innego, wiadomo, że tam leci prawilny obiekt.

2

Chodzi o metodę run, przecież napisałem. Jeśli serwis akceptuje w tej metodzie obiekty klasy A, a obiekty klasy A są zawsze zwalidowane, bo tworzone metodą statyczną i nie da się zrobić kulawych obiektów jakimś konstruktorem, to w serwisie nie potrzebujesz walidacji wejścia. Np.:

class Service {
    void run(LocalDate o) {
        o.getYear();
    }
}

Jeśli o nie jest nullem, to zawsze możesz bezpiecznie wywołać getYear(), który zwróci Ci poprawny wynik. Spróbuj bez magii zrobić obiekt LocalDate z datą 30-02-2020. No chyba, że nie chodzi o walidację, ale sprawdzanie, czy poprawny obiekt spełnia jakiś warunek serwisu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1