2015-05-22 11 views
11

tôi có ba lớp (Số sẽ được thể phát triển trong tương lai):danh sách Overriding và thực hành Java

public inteface Base{ } 

public class Select implements Base{ } 

public class Ast implements Base{ } 

public class Gt implements Base{ } 

Tôi cũng cần trong một lớp học 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){ } 
} 

Lý do tại sao tôi đã làm đây là một thực tế rằng tôi không muốn bất cứ ai để thêm các yếu tố thông qua một con trỏ đến Base. Trong tình huống cụ thể của tôi, điều này sẽ không an toàn.

Nhưng bất lợi là nó sẽ chỉ được phát hiện khi chạy.

Tôi cũng cần phải lặp qua danh sách.

Có thực hành tốt để làm những việc như vậy không?

+6

Có nhiều khả năng tất cả điều này là lạm dụng thừa kế. Tôi muốn đặt cược rằng bất cứ điều gì bạn có trong tâm trí có thể được thực hiện với thành phần. – duffymo

+3

@duffymo Có lẽ bạn có thể đưa ra một ví dụ để hiểu những điều bạn đang nói về? –

+0

"Thành phần" có nghĩa là có một 'ArrayList' là một trường thay vì mở rộng một' ArrayList'. (Xem câu trả lời của tôi hoặc của thành viên cho mã ví dụ.) – aioobe

Trả lời

12

Sử dụng interface là tốt. (Biến Base thành một lớp trừu tượng sẽ không mua bất cứ thứ gì ở đây.)

Bạn nên ủng hộ thành phần trên thừa kế ở đây mặc dù, và thực hiện Iterable<Base> để có thể sử dụng nó trong tăng cường cho vòng, vv

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(); 
    } 
} 

Sau đó, bạn có thể lặp qua danh sách như sau:

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

sử dụng 'Collections.unmodifiableList (danh sách) .iterator()' hạn chế trình lặp này chỉ dành cho mục đích đi ngang. Điều này có nghĩa là gì? Điều này có vẻ như hạn chế không cần thiết để giảm thiểu sức mạnh và lợi ích của 'Iterator'. – TheCurious

+0

@ dubey-theHarcortians, đã cấp điều này là vấn đề thiết kế, và nó không nhất thiết phải là điều đúng đắn để làm. Nó làm tăng sự đóng gói mặc dù, do đó, đó là điều phòng thủ để làm ở đây. Nếu OP chọn thêm phương thức 'remove' vào' BaseList', thì 'unmodifiableList' chắc chắn sẽ bị loại bỏ. – aioobe

7

Bạn có thể tạo Base một lớp abstract, vì chúng không bao giờ có thể được khởi tạo, danh sách của bạn sẽ an toàn.

Cách của tôi: Tôi thực sự không hiểu tại sao bạn muốn ném ngoại lệ cho add(Base b) khi cơ sở là interface mà bản thân nó không bao giờ có thể là một đối tượng.

Nếu không, hãy sử dụng mẫu đại biểu/trình bao bọc, có nghĩa là: Không mở rộng ArrayList, nhưng tạo một lớp giữ một ArrayList.

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

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

re: điểm đầu tiên, bạn vẫn có thể khởi tạo một lớp con, nhưng có một tham chiếu kiểu 'Base'. Sử dụng đại biểu - ngay trên, gợi ý tốt. – vikingsteve

+2

Tôi không thấy làm thế nào để làm cho 'Base' một lớp trừu tượng sẽ làm cho bất kỳ sự khác biệt. Các quy tắc tương tự liên quan đến instantiation cũng áp dụng cho các giao diện. – aioobe

+0

Nhưng tôi sẽ không thể lặp qua BaseList với vòng lặp foreach sau đó. Điều đó không tốt lắm. –

Các vấn đề liên quan