Dekorator wzór
bym faktycznie polecam owijania ArrayList
stosując dobrze udokumentowany Decorator wzór. Wystarczy owinąć ArrayList
z inną realizacją List
że delegaci większość metod ale dodaje logikę walidacji
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
}
Zalety:
- nadal można uzyskać dostęp surowe liście bez sprawdzania, czy chcesz (ale można ogranicz to)
- Łatwiejsze układanie różnych sprawdzeń, włączanie i wyłączanie selektywnie.
- Promuje composition over inheritance jak zauważył @helios
- Poprawia testowalności
- nie wiąże Cię do konkretnej implementacji
List
można dodać walidację do LinkedList
lub Hibernate -backed uporczywe list. Możesz nawet pomyśleć o dekoratorze generycznym Collection
, aby sprawdzić poprawność dowolnej kolekcji.
Wdrażanie zauważa
Pomimo realizacji Pamiętam istnieje sporo metod trzeba pamiętać o jednocześnie nadrzędne: (?) add()
, addAll()
, set()
, subList()
itp
również Twoim obiekt musi być niezmienny, w przeciwnym razie użytkownik może dodać/ustawić poprawny obiekt i zmodyfikować go później, aby naruszyć umowę.
Dobry projekt OO
Finaly pisałem:
validate(element)
ale rozważenia:
element.validate()
który jest lepszy design.
Stacking validations
Jak wspomniano wcześniej, jeśli chcesz stos walidacji, weryfikacji każdego proprty/apsect w jednym, oddzielne klasy, należy rozważyć następujące idiom:
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);
}
... i kilka implementacji :
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
}
}
Chcę tylko sprawdzić foo?
List<MyBusinessObject> list = new FooValidatingDecorator(rawArrayList);
Chcesz zweryfikować zarówno foo i poprzeczkę?
List<MyBusinessObject> list =
new BarValidatingDecorator(new FooValidatingDecorator(rawArrayList));
+1 za kompozycję dotyczącą dziedziczenia! – helios
+1 Dzięki za bardzo szczegółową odpowiedź – Sudhakar