modello Decorator
vorrei davvero raccomandare avvolgendo ArrayList
utilizzando ben documentata Decorator modello. È sufficiente avvolgere il vostro ArrayList
con un'altra List
implementazione che i delegati maggior parte dei metodi, ma aggiunge la logica di convalida:
public class ValidatingListDecorator extends AbstractList<MyBusinessObject>
{
private final List<MyBusinessObject> target;
public ValidatingListDecorator(List<MyBusinessObject> target) {
this.target = target;
}
@Override
public MyBusinessObject set(int index, MyBusinessObject element)
{
validate(element);
return target.set(index, element);
}
@Override
public boolean add(MyBusinessObject o)
{
validate(o);
return target.add(o);
}
//few more to implement
}
Vantaggi:
- è ancora possibile accedere elenco grezzo senza convalida se si vuole (ma si può limitare questo)
- Più facile impilare diverse convalide, attivarle e disattivarle in modo selettivo.
- Promuove composition over inheritance come notato da @helios
- Migliora testability
- non ti legare ad una specifica
List
implementazione, è possibile aggiungere la convalida di LinkedList
o Hibernate emessi a fronte di liste persistenti. Puoi anche pensare al decoratore Collection
generico per convalidare qualsiasi collezione.
Note applicative
Nonostante l'attuazione Ricorda che ci sono un sacco di metodi che dovete ricordare circa mentre l'override: (?) add()
, addAll()
, set()
, subList()
, ecc
anche il tuo l'oggetto deve essere immutabile, altrimenti l'utente può aggiungere/impostare un oggetto valido e modificarlo in seguito per violare il contratto.
buona progettazione OO
Finaly ho scritto:
validate(element)
ma prendere in considerazione:
element.validate()
che è un design migliore.
impilabili convalide
Come notato prima, se si desidera impilare le convalide, convalidando ogni proprty/Apsect in un unico, classe separata, si consideri il seguente linguaggio:
public abstract class ValidatingListDecorator extends AbstractList<MyBusinessObject>
{
private final List<MyBusinessObject> target;
public ValidatingListDecorator(List<MyBusinessObject> target) {
this.target = target;
}
@Override
public MyBusinessObject set(int index, MyBusinessObject element)
{
validate(element);
return target.set(index, element);
}
protected abstract void validate(MyBusinessObject element);
}
... e poche implementazioni :
class FooValidatingDecorator extends ValidatingListDecorator {
public FooValidatingDecorator(List<MyBusinessObject> target)
{
super(target);
}
@Override
protected void validate(MyBusinessObject element)
{
//throw if "foo" not met
}
}
class BarValidatingDecorator extends ValidatingListDecorator {
public BarValidatingDecorator(List<MyBusinessObject> target)
{
super(target);
}
@Override
protected void validate(MyBusinessObject element)
{
//throw if "bar" not met
}
}
desidera convalidare solo foo?
List<MyBusinessObject> list = new FooValidatingDecorator(rawArrayList);
desidera convalidare sia foo e bar?
List<MyBusinessObject> list =
new BarValidatingDecorator(new FooValidatingDecorator(rawArrayList));
+1 per la composizione sull'ereditarietà! – helios
+1 Grazie per la risposta molto dettagliata – Sudhakar