Non conosco il nome del pattern (ma probabilmente usa il pattern Reflection, vedi sotto), ma molti framework Web implementano nativamente ciò che stai tentando di fare qui.
Ad esempio, se guardi Ruby on Rails, ActiveRecord e Mongoid sono i componenti utilizzati per rappresentare un'entità Database e di solito i programmatori implementano il loro modello in questo modo:
class User
include Mongoid::Document # Mongoid is an ORM for MongoDB/noSQL database
# The attributes of your model
field :name
field :email
field :telephone
# Validation rules that guarantee consistency of your instances
validates_presence_of(:name, :email)
validates_uniqueness_of(:email)
validates :telephone { maximum: 10}
...
end
Quindi ciò che succede è che ogni volta che provi a salvare la tua risorsa nel database, tutte le convalide verranno eseguite prima e impedirai di salvare modelli sbagliati.
Direi che il modo migliore per andare è tenere un elenco di tutte le convalide che devi eseguire sulla tua classe. Puoi anche delegare queste convalide a una classe Validator ma ecco come farei (stile Java):
abstract class ValidatableItem
private List<Validation> toValidate;
protected validate(Field a, ValidationType type)
toValidate.push(type.getValidationFor(this, a))
end
private boolean runValidations(){
for(Validation v : toValidate){
if(v.isNotValid())
return false;
}
return true;
}
private Field field(String s){
return this.getclass.getDeclaredField("s")
}
}
class ItemA extends ValidatableItem
Attribute attrA;
Attribute attrB
void validations(){
validate(field("attrA"), ValidationType.EXISTS)
validate(field("attrB"), ValidationType.NON_NEGATIVE)
}
E devi definire tu stesso i tuoi tipi di convalida / convalida.
Modifica
Purtroppo non vedo un altro modo, ma usare Reflection per farlo. Questo può trasformarsi rapidamente in un antipattern. Non ho usato molto il reflection in Java, ma ecco come lo farei.
class WebPage extends ValidatableItem{
String url;
String name;
int vistiCount;
Date lastVisit;
void validations(){
validate(field("visitCount"), ValidationType.EXISTS)
validate(field("url"), ValidationType.VALID_URL)
}
}
public abstract class Validation{
private Class<? extends ValidatableItem> instanceToValidate;
private Field fieldToValidate;
public Validation(Class<? extends ValidatableItem> c, Field f){
this.instanceToValidate = c;
this.fieldToValidate = f;
}
public abstract boolean isNotValid();
}
class ExistValidation extends Validation{
// Redefine same constructor as base class, use super()
public isNotValid(){
return(f.get(c) == null);
}
}
class ValidUrlValidation extends Validation{
// Redefine same constructor as base class, use super()
public isNotValid(){
return(urlRegexMatches(f.get(c));
}
}
Enum ValidationType{
EXISTS(ExistValidation.class)
VALID_URL(ValidUrlValidation.class)
private final Class<? implements Validation> vclass;
private ValidationTypes(Class<? implements Validation> c){
this.vclass = c
}
public getValidation(Class<? extends ValidatableItem> cl, Field f)
// Assume all Validation constructors look the same
return cl.getConstructor(ValidatableItem.class, Field.class).newInstance(cl, f)
}
Nota: non capisco davvero il contesto perché è necessario "convalidare" i tuoi input, ma a meno che tu non debba fare cose molto specifiche, molto probabilmente troverai le librerie che fanno già ciò che vuoi. Ricorda i 7 peccati capitali degli sviluppatori.