2015-05-22 11 views
11

mam trzy klasy (liczba będzie prawdopodobnie rosnąć w przyszłości):Zastępowanie lista i praktyka Java

public inteface Base{ } 

public class Select implements Base{ } 

public class Ast implements Base{ } 

public class Gt implements Base{ } 

również potrzebne w klasie List

BaseList extends ArrayList<Base>{ 
    public boolean add(Base b){ 
     throw new UnsupportedOperationException("You should use add%ConcereteBaseType% method instead"); 
    } 

    public boolean add(Select s){ } 

    public boolean add(Ast a){ } 

    public boolean add(Gt g){ } 
} 

Powodem, dlaczego to zrobiłem był to fakt, że nie chcę, aby ktokolwiek dodawał elementy za pomocą wskaźnika do Base. W mojej konkretnej sytuacji byłoby to niebezpieczne.

Jednak wadą jest to, że zostanie wykryte tylko w czasie wykonywania.

Potrzebuję również do iteracji na liście.

Czy to dobra praktyka, aby robić takie rzeczy?

+6

Jest bardziej prawdopodobne, że to wszystko jest nadużyciem dziedziczenia. Założę się, że cokolwiek masz na myśli, można osiągnąć kompozycją. – duffymo

+3

@ Duffymo Może możesz podać przykład, aby zrozumieć rzeczy, o których mówisz? –

+0

"Kompozycja" oznacza posiadanie 'ArrayList' jako pola zamiast rozszerzania' ArrayList'. (Zobacz na przykład odpowiedź mojego lub członków) na przykład.) – aioobe

Odpowiedz

12

Korzystanie z interface jest w porządku. (Włączanie Base do klasy abstrakcyjnej nie kupi nic tutaj).

Należy sprzyjać kompozycję nad dziedziczenie tutaj choć i wdrożyć Iterable<Base> aby móc używać go w wzmocnione pętle itp

class BaseList implements Iterable<Base> { 
    private List<Base> list = new ArrayList<>(); 

    public boolean add(Select s) { 
     return list.add(s); 
    } 

    public boolean add(Ast a) { 
     return list.add(a); 
    } 

    public boolean add(Gt gt) { 
     return list.add(gt); 
    } 

    @Override 
    public Iterator<Base> iterator() { 
     return Collections.unmodifiableList(list).iterator(); 
    } 
} 

Następnie można powtórzyć listę w następujący sposób:

for (Base b : yourBaseList) { 
    ... 
} 
+0

za pomocą "Collections.unmodifiableList (list) .iterator()" ograniczają ten iterator tylko do celów przemieszczania. Dlaczego to powinno? To wydaje się niepotrzebne ograniczenie, aby złagodzić moc i zalety "Iterator". – TheCurious

+0

@ dubey-theHarcortians, przyznał, że jest to kwestia projektu i niekoniecznie jest to właściwe. Zwiększa jednak hermetyzację, więc jest to defensywne. Jeśli OP zdecyduje się na przykład dodać metodę 'remove' do' BaseList', to 'unmodifiableList' powinno definitywnie zostać usunięte. – aioobe

7

Można utworzyć klasę Base i abstract, ponieważ nigdy nie można utworzyć instancji, Twoja lista będzie bezpieczna.

Mój sposób: Naprawdę nie rozumiem, dlaczego chciałbyś rzucić wyjątek dla add(Base b), gdy baza jest interface, która sama nigdy nie może być obiektem.

W przeciwnym razie należy użyć schematu typu "przenosić/zawijać", oznacza to: Nie należy rozszerzać ArrayList, ale należy utworzyć klasę , która ma i ArrayList.

class BaseList { 
    private List<Base> list = new ArrayList<>(); 

    public boolean add(Select s) { 
     return list.add(s); 
    } 
    //etc 
} 
+0

re: pierwszy punkt, wciąż można utworzyć instancję podklasy, ale mieć odwołanie typu 'Base'. Korzystanie z delegata - od razu, dobra sugestia. – vikingsteve

+2

Nie rozumiem, w jaki sposób uczynienie "Bazy" klasą abstrakcyjną ma znaczenie. Te same zasady dotyczące tworzenia instancji dotyczą również interfejsów. – aioobe

+0

Ale nie będę w stanie powtórzyć powyżej BaseList pętli foreach. To nie jest zbyt dobre. –