2012-02-20 20 views
7

Chciałbym dodać kolekcję obiektów do tablicyList, tylko jeśli dany atrybut nie jest pusty.Czy powinienem rozszerzyć ArrayList, aby dodać atrybuty, które nie mają wartości NULL?

Mam na myśli rozszerzenie ArrayList i wdrożenie kontroli wewnątrz klasy dziecka.

Alternatywnym sposobem jest sprawdzenie atrybutu przed umieszczeniem go w tablicy, ale to by znaczyło, będę musiała rozpraszać, jeśli sprawdza wszędzie gdzie muszę dodać obiekty do listy kontrolnej w oparciu o logikę .

Chciałbym poznać twoje przemyślenia na ten temat ... w drugiej chwili jest to przesada?

Odpowiedz

20

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)); 
+6

+1 za kompozycję dotyczącą dziedziczenia! – helios

+0

+1 Dzięki za bardzo szczegółową odpowiedź – Sudhakar

1

Jeśli chcesz to wymusić, nie widzę powodu, dlaczego nie (mimo że powinieneś sprawdzić wartość zwracaną metody dodawania za każdym razem, gdy ją dodasz, aby upewnić się, że się udało).

Jest to dobry sposób na pozbycie się tej nadmiarowej logiki, która może lub nie musi pozostać w późniejszych iteracjach oprogramowania.

+0

Zgadzam się z Tobą, ale IMO jest jeden kompromis podczas rozszerzania z pewnej implementacji listy - nie można przejść do innej strategii, np. zamień ArrayList na LinkedList. Delegacja byłaby inną opcją. – home

+0

@home Sortuj, łatwo jest przełączyć coś, co rozszerza listę tablicową na coś, co rozszerza coś innego, o ile oba interfejsy są dokładnie takie same lub nieco bliskie. –

+0

Znowu zgodziłem się. +1 – home

0

Jedynym problemem będzie ponowne użycie tego kodu i nie pamiętasz, że przerobiłeś klasę ArrayList. Pamiętaj o dokładnym komentarzu.

1

Nie sądzę, że jest to dobra praktyka. Zastanów się, zamiast pisać metodę Util w klasie użytkowej, biorąc dwa parametry: listę tablic i obiekt, który chcesz dodać. Tam możesz sprawdzić, co chcesz i możesz ponownie wykorzystać logikę całego kodu.