2010-01-14 32 views
6

Hôm nay tôi nhìn vào lớp ZipEntry và thấy như sau:Một lớp có nên triển khai một giao diện chỉ có hằng số không?

public class ZipEntry implements ZipConstants, Cloneable 

ZipConstants không xác định bất kỳ phương pháp - chỉ hằng (static final int LOCHDR = 30)

Sau đó nó xảy ra với tôi rằng việc thực hiện các giao diện với các hằng số cho phép bạn truy cập trực tiếp các hằng số đó, như thể chúng được định nghĩa trong chính lớp đó. Ví dụ:

public interface Constants { 
    static final int CONST = 2; 
} 

public class implements Constants { 
    int doSomething(int input) { 
     return CONST * input; 
    } 
} 

Có một lý do không sử dụng điều này, ngoài việc:

  • nó được lúc đầu khó hiểu nơi hằng số đến từ
  • nó được coi là sai lầm khi sử dụng giao diện cho hằng số định nghĩa

Tôi tò mò vì nó chắc chắn không phải là một thực tế rất phổ biến.

Trả lời

16

lý do khác không sử dụng này:

Kể từ Java 5, có một tính năng ngôn ngữ "sạch" mà đạt được cùng một mục tiêu: static imports.

Thực hiện các giao diện để sử dụng hằng số về cơ bản là một bản tiền Java-5 hack để mô phỏng nhập khẩu tĩnh.

+0

(+1), nó không mô phỏng nó hoàn toàn, bởi vì nó không hoạt động cho nhập khẩu tĩnh các phương thức – Bozho

+0

Thực ra, có một số logic tròn trong đối số này. Chúng tôi không kế thừa các lớp duy nhất liên tục vì bạn có thể sử dụng nhập tĩnh. Nhưng tại sao chúng ta nên sử dụng nhập khẩu tĩnh cho rằng chúng ta có thể kế thừa giao diện? Ngay cả gọi nó là một "hack" mà không nói lý do tại sao nó được coi là một "hack" giống như lặp lại câu thần chú "phong cách xấu". –

+0

Sự khác biệt là nhập khẩu tĩnh là một tính năng ngôn ngữ được giới thiệu cụ thể để cho phép điều này, trong khi mục đích của giao diện là khá khác nhau; do đó, bằng cách sử dụng một giao diện như thế này là một hack; Tôi nghĩ điều đó không cần nói. –

2

... bởi vì nó được coi là sai lầm khi sử dụng giao diện cho hằng số định nghĩa

Đây là một lý do xấu không làm điều gì đó. Trong thực tế, nó không phải là một lý do nào cả.

EDIT

Xem xét việc này.

  • Lý do XXX là kiểu xấu là YYY.
  • Lý do bạn nên làm XXX là kiểu xấu.

Có bao nhiêu lý do chính đáng để không thực hiện XXX? Một hoặc hai?

Nếu câu trả lời là hai, tôi có thể làm cho nó ba, bốn, năm, v.v. bằng cách thêm các chuỗi lý do liên tục. Ví dụ: "Lý do bạn không nên làm XXX là vì đó là ý tưởng tồi". "Những lý do đó là một ý tưởng tồi là nó là phong cách xấu". Và cứ thế. Đó là rõ ràng ngớ ngẩn.

Không thực lý do không thực hiện XXX là YYY và lý do "Kiểu xấu" không phải là lý do chính đáng. Thay vào đó, nó là một đoạn cắt ngắn để nói rằng đừng làm XXX vì YYY và ZZZ, và bất kỳ lý do chính đáng nào khác.

Thực tế, ngay cả lý do "gây nhầm lẫn" của OP không được nêu đầy đủ. Tại sao nó khó hiểu?

Vì giao diện thường là loại có các lớp triển khai giao diện là loại phụ. Nhưng một giao diện duy nhất liên tục không phải là một loại trong bất kỳ ý nghĩa hữu ích nào, và các lớp thực hiện giao diện không phải là các kiểu con theo bất kỳ ý nghĩa hữu ích nào. Cuối cùng, đây là lý do thực sự mà triển khai các giao diện duy nhất liên tục được gọi là kiểu xấu và "chống mẫu", và đó là lý do chính khiến các nhập tĩnh được thêm vào trong Java 5.

+0

vì đó là vấn đề về kiểu mã, vì lý do kiểu mã cho một vấn đề kiểu mã khác không quá lạ. – Bozho

3

Nó không quá hiếm như bạn có thể nghĩ, ví dụ trong phân tích tĩnh của Parasofts JTest cả quy tắc mà các hằng số phải được khai báo trong một class và quy tắc mà các hằng số phải được khai báo trong interface s có mặt và tùy thuộc vào dự án để chọn giữa chúng.

Điều đó nói rằng, trong tất cả các dự án của tôi, tôi không cho phép thực hành xác định hằng số trong giao diện. Việc tạo một lớp có ý nghĩa và rõ ràng về ngữ cảnh của một hằng số làm cho mã dễ đọc hơn và do đó có thể duy trì hơn trong trường hợp nhà phát triển phải kiểm tra các hằng số được sử dụng trong một lớp thực sự giống với các lớp trong một lớp khác (hay không).)

0

Không, điều này còn được gọi là "Mô hình giao diện không đổi". Một cách khác là viết một lớp cụ thể định nghĩa các hằng số và sau đó sử dụng nhập tĩnh.

Lớp Constants

package util; 

public class Constants { 
    public static final String CONSTANT_STRING = "abc"; 

    private Constants() { 
     throw new AssertionError(); 
    } 
} 

Lớp Kiểm tra

import static util.Constants.CONSTANT_STRING; 

public class Test { 
    System.out.println(CONSTANT_STRING); 
} 

Xem

Wikipedia

để biết thêm chi tiết.

+0

Tôi biết những gì nhập khẩu tĩnh là;) – Bozho

0

Một trong những lý do không đặt hằng số của bạn trong giao diện là nếu bạn để lộ giao diện của mình cho bên thứ ba, họ có quyền truy cập vào các hằng số của bạn. Điều này có vẻ không phải là một ý tưởng tồi để bắt đầu nhưng hãy tưởng tượng nếu bạn muốn thay đổi giá trị của một hằng số nhưng mọi người vẫn đang sử dụng một giao diện cũ.

Khi bạn thêm thứ gì đó vào giao diện, nó có khả năng được đặt trong đá để chỉ thêm những gì bạn muốn người khác xem và sử dụng.

2

Tôi nghĩ rằng việc sử dụng một giao diện cho hằng chia sẻ là một ví dụ về nhầm lẫn hai khái niệm khác nhau:

  1. Mã tái sử dụng
  2. subtyping

Theo kinh nghiệm của tôi sử dụng subclassing, hoặc giao diện thực hiện đơn giản để ngăn chặn việc sao chép mã dẫn đến sự cố. Mã của bạn trở nên mong manh hơn. Ví dụ: ai đó có thể vô tình xác định lại hằng số - đặc biệt nếu phân cấp lớp của bạn có nhiều lớp sâu.

Tốt hơn nên sử dụng bố cục để giữ mã của bạn KHÔ.

Một vấn đề khác khi sử dụng thừa kế theo cách này là nói chung loại thừa kế này tạo thành một phần của API của lớp học của bạn. Hệ thống phân cấp của lớp được hiển thị bên ngoài lớp. Điều này phá vỡ đóng gói.Bạn không cần phải vạch trần việc sử dụng các hằng số bên ngoài lớp, chúng phải làm với cách bạn đã chọn để triển khai lớp học của bạn và không phải là một phần của API của nó (trong ví dụ của bạn).

Điều này có thể dẫn đến các sự cố tương thích ngược đáng kinh ngạc. Một người nào khác có thể đến và viết mã như thế này:

public interface Constants { 
    static final int CONST = 2; 
} 

public class MyClass implements Constants { 
    int doSomething(int input) { 
    return CONST * input; 
    } 
} 

public class ThirdPartyClass { 
    int doSomethingElse(int input) { 
    return MyClass.CONST + input; 
    } 
} 

Bây giờ, nếu bạn quyết định không còn cần phải sử dụng CONST trong MyClass thì bạn đang mắc kẹt. Bởi vì ThirdPartyClass đã tạo ra một sự phụ thuộc vào CONST có sẵn trong MyClass.

Bạn có thể kết thúc với điều này. Trường hợp MyClass không sử dụng bất kỳ hằng số nào trong giao diện, nhưng vẫn phải thực hiện nó.

public interface Constants { 
    static final int CONST = 2; 
} 

public class MyClass implements Constants { 
    int doSomething(int input) { 
    return input; 
    } 
} 

public class ThirdPartyClass { 
    int doSomethingElse(int input) { 
    return MyClass.CONST + input; 
    } 
} 

Tóm lại; không bao giờ làm điều này!

+0

Tôi đã không có ý định làm điều đó, tôi đã chỉ tò mò tại sao nó đã được thực hiện trong một API mặt trời cung cấp – Bozho

+0

Thiếu kinh nghiệm có thể? Tôi đã làm điều đó trong quá khứ, trước khi tôi nhận ra loại vấn đề mà nó có thể gây ra. Hoặc có thể nó đã được quyết định như là một quy ước mã một thời gian dài trước đây, và bây giờ các nhà phát triển mặt trời cảm thấy họ đang bị mắc kẹt sau nó? Tôi đoán là ... – lexicalscope

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