2008-12-12 32 views
13

Câu hỏi của tôi là, nếu một giao diện được triển khai ngầm định bằng cách mở rộng một lớp đã triển khai nó, cần được lớp thực hiện một cách rõ ràng, nếu lớp muốn quảng cáo sự kiện, nó thỏa mãn hợp đồng của giao diện đó.Một giao diện được thừa hưởng từ lớp cơ sở có được triển khai rõ ràng trong phân lớp không?

Ví dụ: nếu bạn muốn viết một lớp, thỏa mãn hợp đồng của giao diện java.util.List. Bạn thực hiện điều này, mở rộng lớp java.util.AbstractList, đã triển khai giao diện List. Bạn có khai báo rõ ràng rằng bạn triển khai Danh sách không?

public class MyList extends AbstractList implements List 

Hoặc bạn lưu gõ bằng cách sử dụng ngầm?

public class MyList extends AbstractList 

Cách nào được coi là phong cách tốt hơn? Lý do nào bạn phải thích cách này hay cách khác? Trong trường hợp nào bạn thích cách 1 hoặc cách 2?

+0

Tôi nghĩ đó là một câu hỏi hay. – Uri

+0

Từ quan điểm về khả năng sử dụng, nó có thể có ý nghĩa nếu nó không rõ ràng từ tên lớp mà nó thực hiện giao diện. – Uri

Trả lời

4

Tôi đã hỏi this same question long ago on my blog. Có một cuộc thảo luận dài ở đó là tốt nếu bạn quan tâm đến việc thấy suy nghĩ của người khác. Thật thú vị khi lưu ý rằng cả hai chiến lược đều được thực hiện trong JDK.

Cuối cùng tôi quyết định rằng một quy tắc khó về điều này không có ý nghĩa - tốt hơn là nên sử dụng phán đoán tốt nhất về những gì tôi muốn giao tiếp.

12

Tránh dự phòng. Sử dụng phương pháp 2.

Sử dụng @Override để ghi đè.

7

Đây không phải là câu hỏi "kiểu". Nếu bạn đang mở rộng AbstractList đã triển khai Danh sách, bạn không cần phải triển khai Danh sách rõ ràng.

Nó không chỉ là một câu hỏi tiết kiệm gõ. Khi bổ sung "danh sách thực hiện" là dư thừa, ai đó có thể dành một chút thời gian cố gắng tìm ra lý do tại sao nó ở đó. Về cơ bản, bạn đang viết thư bảo đảm đã là một phần của ngôn ngữ.

+5

Điều gì sẽ xảy ra nếu ai đó thay đổi AbstractList để không còn triển khai Danh sách nữa? Sau đó, MyList bị hỏng? Tôi không nghĩ đây là một lý lẽ mạnh mẽ mà chỉ là người ủng hộ ma quỷ. –

+0

Tôi muốn +1 nhận xét của Alex. – Uri

+0

Vâng, sau đó, trong cả hai trường hợp nó bị hỏng. Nếu bạn muốn triển khai AbstractList cũng như List, bạn có nghĩa là cái gì đó không thực sự có ý nghĩa gì khi List đã triển khai AbstractList. Nếu ai đó sau đó đến và thay đổi Danh sách để nó không còn triển khai AbstractList nữa, thì chắc chắn, "thực hiện" bổ sung của bạn có nghĩa là gì đó, nhưng theo nghĩa đen, nó không phải là thứ bạn có thể hiểu hoặc dự định khi bạn viết Danh sách của mình nơi đầu tiên. –

0

Khi bạn mở rộng AbstractList, MyList là danh sách 'loại' đã có, do đó, không cần phải khai báo một cách rõ ràng (hoặc triển khai) giao diện.

1

Tôi sẽ nói cách nguyên văn hơn. Tại sao làm cho người khác đọc mã của bạn phải tìm kiếm những gì một lớp thực hiện? Nó làm cho nó rõ ràng về các chức năng kế thừa của lớp học của bạn. Nhưng tôi sẽ cố gắng duy trì tính thống nhất trên tất cả các mã trong dự án. Nó sẽ gây nhầm lẫn nếu bạn chỉ làm điều đó ở một nơi nhưng nếu bạn làm điều đó một cách nhất quán họ sẽ nhận thức được sự thừa.

Ghi chú bên: Có quá nhiều lớp trong Java và ai biết tất cả? Thậm chí nhiều hơn như vậy, ai biết được những lớp học mỗi lớp thực hiện từ đâu? Bạn gõ cho một vài giây thêm tiết kiệm một nhà phát triển đồng nghiệp một hoặc hai phút tìm kiếm các lớp học.

1

Người nhận xét khác nói rằng bạn nên tránh dự phòng và tôi đồng ý với họ.

Để trả lời câu hỏi chung, trường hợp duy nhất tôi có thể nghĩ đến cho cả hai sẽ là nếu bạn mở rộng (giả sử) AbstractFrotzer và triển khai Frobner, AbstractFrotzer đã triển khai Frobner, nhưng bạn có lý do để tin rằng nó có thể không có trong Tương lai. Nếu AbstractFrotzer thực sự là trừu tượng, thì nó thậm chí có thể không thực hiện tất cả các phương thức của Frobner. Điều này có nghĩa là một người có thể thay đổi hợp đồng cho AbstractFrotzer mà không cần phải thay đổi lớp học của bạn, hoặc bất kỳ mã nào khác dựa vào lớp học của bạn để trở thành một Frobner. Tuy nhiên, tôi cho rằng đây là một tình huống rất hiếm, và ngay cả khi nó xảy ra và lớp của bạn chỉ mở rộng AbstractFrotzer, nó sẽ đủ dễ dàng để kiểm tra ngữ nghĩa nhanh chóng, và nếu cần, hãy thêm mệnh đề thực hiện vào nó điểm đó.

0

Theo nguyên tắc chung, sử dụng phương án 2, không lựa chọn 1.

Lựa chọn 1 không cung cấp bất kỳ giá trị gia tăng cho nhà phát triển hay bất kì ai đang xảy ra để duy trì các mã, trong đại đa số các trường hợp.

Nếu ai đó thực sự muốn biết tất cả các số nguồn gốc của một lớp cụ thể, bất kỳ IDE nào cũng có thể làm điều đó cho bạn, đơn giản. (Eclipse: ctrl + shift + G)

Điều gì xảy ra nếu AbstractList quyết định không triển khai Danh sách nữa? Điều này sẽ không xảy ra cho đại đa số các lớp học chung. Còn điều gì khác ít rõ ràng hơn (ít hơn đáng tin cậy)? Tất nhiên có thể có ngoại lệ, nhưng rất ít (< 1%?)

1

Trong khi tôi thường gắn với tùy chọn 2, tôi sẽ đi trên chi và cho rằng tùy chọn 1 thực sự thích hợp trong nhiều trường hợp khi nó được áp dụng.

Tính khả dụng của mã và tính dễ hiểu là quan trọng. Câu hỏi mà chúng ta phải tự hỏi là liệu một nhà phát triển có sử dụng hoặc thấy một tham chiếu đến lớp này sẽ trực giác hiểu rằng lớp thực hiện giao diện đó (và do đó về cơ bản là một kiểu con).

Trong một lớp được viết tốt trong trường hợp điển hình, tên của lớp sẽ làm cho nó rõ ràng là nó thực hiện giao diện. Thêm giao diện sẽ chỉ là một sự thừa.

Tuy nhiên, trong trường hợp tên lớp không làm cho nó rõ ràng những gì giao diện nó thực hiện, và mặc dù mùi đây là cách mọi việc và đây là tên sẽ bị mắc kẹt, sau đó nó làm cho tinh thần để thêm các thực hiện để chỉ ra giao diện một cách rõ ràng. Điều này cũng tốt trong trường hợp một người nào đó trong tương lai thay đổi hệ thống phân cấp, điều này có thể xảy ra trong các thừa kế không trực quan như thế này.

0

Tôi đã thấy điều này trước đây và nó không cảm thấy đúng về mặt kỹ thuật, như nhiều bạn đã chỉ ra. Tôi sẽ nghĩ rằng nó nên được rõ ràng, tuy nhiên nếu vì một lý do nó không phải là tôi nghĩ rằng nó sẽ có ý nghĩa hơn để chỉ ra các thừa kế thông qua một bình luận lớp, hơn là thực hiện một cách rõ ràng giao diện một lần nữa.

Điều gì sẽ xảy ra nếu lớp cơ sở triển khai nhiều giao diện? Sau đó bạn có thực hiện rõ ràng tất cả các giao diện đó và tất cả các cách sao lưu chuỗi kế thừa không? Rõ ràng là không, vì vậy tôi nghĩ sự mâu thuẫn của cách tiếp cận này chứng minh rằng nó sai. Ý định có thể được truyền đạt theo nhiều cách, và đây không phải là cách tiếp cận tốt nhất IMHO.

2

Nếu bạn quan tâm đến một người dùng trong lớp của bạn có thể nhận được danh sách các giao diện được triển khai thông qua Class.getInterfaces() thì lớp của bạn nên đề cập đến tất cả các giao diện trong danh sách thực hiện của nó. Class.getInterfaces() sẽ không trả về các giao diện được thực hiện bởi các lớp siêu. Chương trình sau đây sẽ in 1 và sau đó là 0.

import java.io.Serializable; 

class Test implements Serializable { 
    class Inner extends Test { 
    } 

    public static void main(String[] argv) throws Exception { 
     System.out.println(Test.class.getInterfaces().length); 
     System.out.println(Inner.class.getInterfaces().length); 
    } 
} 
1

Mặc dù đó là sự thừa để triển khai giao diện trong phân lớp nhưng thực hành tốt là thực hiện nó. Bởi vì ai đó có thể loại bỏ giao diện được triển khai khỏi lớp siêu.

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