Validierung ist häufig ein zusammengesetztes Muster. Wenn Sie es brechen, wollen Sie die trennen, was Sie die zu wollen, wie aus wollen Sie es tun, erhalten Sie:
Wenn foo gültig ist dann etwas tun.
Hier haben wir die Abstraktion ist gültig - Vorbehalt: Dieser Code wurde aus dem aktuellen, ähnliche Beispiele aufgehoben, so dass Sie fehlende Symbolik und so finden können. Aber das ist so, damit Sie das Bild bekommen. Zusätzlich enthält das Objekt Meldungen über den Fehler sowie einen einfachen Status (true/false). Dies ermöglicht Ihnen die Option, einfach zu fragen: "Hat es bestanden?" vs. „Wenn es versäumt, sag mir warum“
QuickCollection
und
QuickMap
Convenience-Klassen sind für jede Klasse und sie schnell in diese respektiert Arten drehen, indem lediglich auf einen Delegierten zuweisen. In diesem Beispiel bedeutet dies, dass Ihr zusammengesetzter Validierer bereits eine Sammlung ist und z. B. iteriert werden kann.
Sie hatten ein sekundäres Problem in Ihrer Frage: "sauber binden" wie in "Typ A" -> Regeln {a, b, c} "und" Typ B "-> Regeln {c, e, z} "
Dies ist leicht mit einer Karte verwaltet. Nicht ganz eine Command pattern aber in der Nähe
Map<Type,Validator> typeValidators = new HashMap<>();
Einrichtung der Validator für jeden Typen dann eine Zuordnung zwischen Typen erstellen.Das ist wirklich am besten als Bean Config getan, wenn Sie mit Hilfe von Java, aber Definitiv Verwendung dependency injection
public interface Validator<T>{
public Result validate(T value);
public static interface Result {
public static final Result OK = new Result() {
@Override
public String getMessage() {
return "OK";
}
@Override
public String toString() {
return "OK";
}
@Override
public boolean isOk() {
return true;
}
};
public boolean isOk();
public String getMessage();
}
}
nun einige einfache Implementierungen, den Punkt zeigen:
public class MinLengthValidator implements Validator<String> {
private final SimpleResult FAILED;
private Integer minLength;
public MinLengthValidator() {
this(8);
}
public MinLengthValidator(Integer minLength) {
this.minLength = minLength;
FAILED = new SimpleResult("Password must be at least "+minLength+" characters",false);
}
@Override
public Result validate(String newPassword) {
return newPassword.length() >= minLength ? Result.OK : FAILED;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Hier ist ein weiteres wir kombinieren mit
public class NotCurrentValidator implements Validator<String> {
@Autowired
@Qualifier("userPasswordEncoder")
private PasswordEncoder encoder;
private static final SimpleResult FAILED = new SimpleResult("Password cannot be your current password",false);
@Override
public Result validate(String newPassword) {
boolean passed = !encoder.matches(newPassword,user.getPassword());
return (passed ? Result.OK : FAILED);
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Jetzt ist hier ein Verbund:
public class CompositePasswordRule extends QuickCollection<Validator> implements Validator<String> {
public CompositeValidator(Collection<Validator> rules) {
super.delegate = rules;
}
public CompositeValidator(Validator<?>... rules) {
super.delegate = Arrays.asList(rules);
}
@Override
public CompositeResult validate(String newPassword) {
CompositeResult result = new CompositeResult(super.delegate.size());
for(Validator rule : super.delegate){
Result temp = rule.validate(newPassword);
if(!temp.isOk())
result.put(rule,temp);
}
return result;
}
public static class CompositeResult extends QuickMap<Validator,Result> implements Result {
private Integer appliedCount;
private CompositeResult(Integer appliedCount) {
super.delegate = VdcCollections.delimitedMap(new HashMap<PasswordRule, Result>(), "-->",", ");
this.appliedCount = appliedCount;
}
@Override
public String getMessage() {
return super.delegate.toString();
}
@Override
public String toString() {
return super.delegate.toString();
}
@Override
public boolean isOk() {
boolean isOk = true;
for (Result r : delegate.values()) {
isOk = r.isOk();
if(!isOk)
break;
}
return isOk;
}
public Integer failCount() {
return this.size();
}
public Integer passCount() {
return appliedCount - this.size();
}
}
}
und nun ein Ausschnitt der Nutzung:
private Validator<String> pwRule = new CompositeValidator<String>(new MinLengthValidator(),new NotCurrentValidator());
Validator.Result result = pwRule.validate(newPassword);
if(!result.isOk())
throw new PasswordConstraintException("%s", result.getMessage());
user.obsoleteCurrentPassword();
user.setPassword(passwordEncoder.encode(newPassword));
user.setPwExpDate(DateTime.now().plusDays(passwordDaysToLive).toDate());
userDao.updateUser(user);
Es ist definitiv nicht eine schlechte Wette. Haben Sie daran gedacht, für jeden Typ separate Ketten oder für alle Typen eine einzelne Kette zu erstellen? – Kayaman
Eine einzelne Kette für alle Typen (weil die Regeln nicht gut segmentieren), aber testen, ob sie für den Datensatz gilt. Ich dachte, dies würde auch das Hinzufügen neuer Regeln erleichtern. (Lesen: einfacher für den Kunden zu verstehen ...) – yamori
Haben Sie erwogen, Drools zu benutzen? –