Giao diện tĩnh có phải là một thực hành tốt?


13

Gần đây tôi đã nhận thấy có một tùy chọn để có các phương thức tĩnh trong giao diện. Tương tự như với các trường tĩnh của giao diện, có một hành vi thú vị: Chúng không được kế thừa.

Tôi không chắc nó có hữu ích trong các giao diện thực tế sẽ được triển khai không. Tuy nhiên, nó cho phép lập trình viên tạo các giao diện chỉ là phong bì cho các công cụ tĩnh, ví dụ như các lớp tiện ích.

Một ví dụ đơn giản chỉ là một phong bì cho các hằng số toàn cầu. So với một lớp, bạn có thể dễ dàng nhận thấy cái nồi hơi bị thiếu public static finalnhư những cái được giả định (làm cho nó ít dài dòng hơn).

public interface Constants {
    String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
    int DEFAULT_TIMEOUT_MS = 30;
}

Bạn cũng có thể làm cho một cái gì đó phức tạp hơn, như giả khóa này của các phím cấu hình.

public interface ConfigKeys {
    static createValues(ConfigKey<?>... values) {
        return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
    }

    static ConfigKey<T> key(Class<T> clazz) {
        return new ConfigKey<>(clazz);
    }

    class ConfigKey<T> {
        private final Class<T> type;
        private ConfigKey(Class<T> type) {
            this.type = type;
        }
        private Class<T> getType() {
            return type;
        }
    }
}

import static ConfigKeys.*;
public interface MyAppConfigKeys {
    ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
    ConfigKey<String> COMPANY_NAME = key(String.class);

    Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);

    static values() {
        return VALUES;
    }
}

Bạn cũng có thể tạo một số "lớp" tiện ích theo cách này. Tuy nhiên, trong các tiện ích, thường hữu ích khi sử dụng các phương thức trợ giúp riêng tư hoặc được bảo vệ, điều này không hoàn toàn khả thi trong các lớp.

Tôi coi đó là một tính năng mới hay và đặc biệt là các thành viên tĩnh không được thừa hưởng là một khái niệm thú vị chỉ được giới thiệu cho các giao diện.

Tôi tự hỏi nếu bạn có thể coi nó là một thực hành tốt. Mặc dù phong cách mã và thực tiễn tốt nhất không phải là tiên đề và có chỗ cho ý kiến, tôi nghĩ thường có những lý do hợp lệ ủng hộ ý kiến.

Tôi quan tâm nhiều hơn đến lý do (không) sử dụng các mẫu như hai loại này.


Lưu ý rằng tôi không có ý định thực hiện các giao diện đó. Họ chỉ đơn thuần là một phong bì cho nội dung tĩnh của họ. Tôi chỉ có ý định sử dụng các hằng hoặc phương thức và có thể sử dụng nhập tĩnh.


1
Phản ứng giật đầu gối của tôi với điều này là nó chỉ có thể dẫn đến những điều xấu. Mặc dù các phương thức tĩnh công khai về cơ bản chỉ là các hàm toàn cầu được đặt tên. Cảm giác như cho phép bất kỳ mã triển khai nào trong Giao diện đi ngược lại mục đích của nó là việc thực hiện vắng mặt định nghĩa hợp đồng. Tôi nói để lại một phần thực hiện cho các lớp Trừu tượng. Tôi sẽ cần phải đọc lên lý do tại sao điều này đã được thêm vào.
Adrian

Tôi phải đi bây giờ nhưng tôi sẽ viết một cái gì đó vào ngày mai trên đó. Tóm lại là trước khi một Giao diện có mục đích rõ ràng được tách biệt rõ ràng với mục đích của Tóm tắt. Bây giờ, chúng trùng lặp rất nhiều theo cách vi phạm định nghĩa bất khả tri ngôn ngữ của Giao diện. Ngoài ra, có những trường hợp bạn không thể kế thừa từ nhiều giao diện nữa nếu chúng thực hiện các phương thức mặc định. Vì vậy, bây giờ có các ngoại lệ đối với kế thừa nhiều giao diện, nơi trước đây không có bất kỳ giao diện nào. Vì Java đã đi chệch khỏi quyết định chung của một giao diện ...
Adrian

nó cũng có thể gây nhầm lẫn cho các nhà phát triển mới, những người đang cố gắng xử lý các khái niệm OOP cơ bản như Giao diện, Tóm tắt, khi nào nên sử dụng thành phần thay vì kế thừa, ... vv.
Adrian

Aliester, bạn đang nói về defaultphương pháp. Tôi đang nói về staticphương pháp và lĩnh vực. Những người không được thừa kế, vì vậy họ không phá vỡ nhiều di sản.
Vlasec

Câu trả lời:


1

Một ví dụ đơn giản chỉ là một phong bì cho các hằng số toàn cầu.

Đặt các hằng số trên các giao diện được gọi là các Constant Interface Antipatternhằng số thường chỉ đơn thuần là một chi tiết triển khai. Hạn chế hơn nữa được tóm tắt trong bài viết Wikipedia trên giao diện Constant .

Bạn cũng có thể tạo một số "lớp" tiện ích theo cách này.

Thật vậy, tài liệu Java nói rằng các phương thức tĩnh có thể giúp tổ chức các phương thức của trình trợ giúp dễ dàng hơn, ví dụ như khi gọi các phương thức của trình trợ giúp từ các phương thức mặc định.


1
Tôi không nghĩ rằng đây thực sự là một câu trả lời cho câu hỏi được đặt ra vì bạn có thể làm cả hai điều này mà không có chức năng mới này.
Adrian

À, vậy theo tài liệu, nó dự định là một phương thức trợ giúp. Tuy nhiên, nó cũng là công khai, mà mâu thuẫn với nó. Vì vậy, có lẽ nó cũng có ý định giúp các lớp thực hiện giao diện. Nhưng chúng không được kế thừa, vì vậy bạn phải sử dụng nhập tĩnh để tạo cảm giác như bạn được thừa hưởng nó. Vâng, cảm ơn vì đã tìm kiếm nó trong các tài liệu.
Vlasec

2
Hoàn toàn không có gì sai khi đặt các hằng số trong các giao diện, nếu các hằng số đó là một phần của API được mô tả bởi giao diện. Điều duy nhất là một antipotype là đưa các hằng vào các giao diện mà không có các phương thức và có các lớp thực hiện giao diện chỉ để tham chiếu các hằng mà không có tiền tố lớp. Đó là sự lạm dụng các giao diện và, kể từ khi giới thiệu nhập khẩu tĩnh, hoàn toàn lỗi thời.
Michael Borgwardt

1

Như đã nêu trong câu hỏi, giao diện không có nghĩa là được thực hiện (hoặc khởi tạo). Vì vậy, chúng ta có thể so sánh nó với một lớp có hàm tạo riêng:

  • Lớp không thể được mở rộng mà không super()gọi, nhưng giao diện có thể được "triển khai"
  • Lớp không thể được khởi tạo mà không có phản xạ, trong khi giao diện có thể dễ dàng được tạo ngay như một lớp ẩn danh đơn giản như sau: new MyInterface() {};

Sự so sánh này có lợi cho lớp vì nó cho phép kiểm soát nhiều hơn. Điều đó nói rằng, lớp cũng không có ý định là người nắm giữ các công cụ tĩnh, bạn mong muốn nó có các thể hiện. Vâng, không có lựa chọn hoàn hảo.

Ngoài ra còn có một điều kỳ lạ về sự kế thừa từ "giao diện tĩnh":

  • Một lớp "thực hiện" kế thừa các trường, nhưng không kế thừa các phương thức tĩnh
  • Một giao diện mở rộng không có thành viên tĩnh nào cả
  • (Trong khi một lớp mở rộng một lớp kế thừa mọi thành viên không riêng tư ... và vì nó không thể được mở rộng bởi một giao diện, nên có ít chỗ hơn cho sự nhầm lẫn)

Đây có thể là những lý do để coi đó là một mẫu xấu và tiếp tục sử dụng các lớp tĩnh cho các trường hợp này. Tuy nhiên, đối với một người nghiện đường cú pháp, nó vẫn có thể hấp dẫn ngay cả với những nhược điểm.


... Dù sao, các quy ước mã hóa của một nhóm có thể bao gồm những vấn đề đó. Đối với tôi, mặc dù nó không ràng buộc chặt chẽ với một lập trình viên gần như một lớp với trình xây dựng riêng, nhưng nó vẫn chịu ít rủi ro hơn so với setters và setters thường được sử dụng.
Vlasec

0

Vì @MarkusPscheidt, ý tưởng này thực chất là một phần mở rộng của antipotype Giao diện không đổi. Cách tiếp cận này ban đầu được sử dụng rộng rãi để cho phép một tập các hằng số được kế thừa bởi nhiều lớp khác nhau. Lý do điều này kết thúc được coi là một antipotype là vì các vấn đề đã gặp phải khi sử dụng phương pháp này trong các dự án thực tế. Tôi thấy không có lý do để nghĩ rằng những vấn đề này sẽ chỉ liên quan đến hằng số.

Có lẽ quan trọng hơn, thực sự không cần phải làm điều này. Thay vào đó, hãy sử dụng nhập tĩnh và rõ ràng về những gì bạn đang nhập và từ đâu.


Đúng, nhập khẩu tĩnh nghe có vẻ là một ý tưởng tốt hơn so với kế thừa các hằng số và nó hoạt động với các thành viên tĩnh của cả hai lớp và giao diện. Và nó chỉ hiển thị bên trong lớp / giao diện.
Vlasec

@Vlasec Đúng nhưng không cần phải làm điều này trên một giao diện. Sự khác biệt duy nhất giữa làm điều này với một lớp và một giao diện là bạn có thể kế thừa từ nhiều hơn một giao diện. Cách thực hành tiêu chuẩn cho một lớp tiện ích như thế này là làm cho hàm tạo riêng tư để ngăn chặn việc khởi tạo hoặc mở rộng. Không có lợi ích để làm điều này trong một giao diện trên một lớp. Nó chỉ đơn giản là mở cửa cho việc sử dụng sai.
JimmyJames

Tôi có thể thấy giá trị trong hằng số trên các giao diện. Các giao diện có xu hướng xác định các phương thức và phương thức đôi khi chấp nhận các hằng số làm tham số. Vd : interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }. Tôi có thể tưởng tượng có một số là hằng số khác nhau RGB, RGBA, CMYK, GREYSCALE, INDEXED, vv
Stijn de Witt

@StijndeWitt Đây sẽ không phải là điều tồi tệ nhất nhưng bạn có thể sử dụng một lớp enum hoặc lớp lồng trên giao diện cho mục đích này. Vấn đề thực sự là sử dụng điều này để đưa statics vào phạm vi của nhiều lớp thông qua kế thừa. Cách tiếp cận đó rõ ràng là kém hơn so với sử dụng nhập khẩu tĩnh.
JimmyJames

0

Tôi sẽ nói, nếu bạn quan tâm đến cách sử dụng tính năng mới đúng cách, hãy xem mã trong JDK. Các phương thức mặc định trên các giao diện được sử dụng rất rộng rãi và dễ tìm, nhưng các phương thức tĩnh trên các giao diện dường như rất không phổ biến. Một số ví dụ bao gồm java.time.chrono.Chronology, java.util.Comparator, java.util.Map, và khá nhiều giao diện trong java.util.functionjava.util.stream.

Hầu hết các ví dụ tôi đã xem xét liên quan đến việc sử dụng các API có khả năng rất phổ biến: chuyển đổi giữa các loại khác nhau trong API thời gian, ví dụ, để so sánh có thể được thực hiện thường xuyên giữa các đối tượng được truyền cho các chức năng hoặc đối tượng có trong bộ sưu tập. Mục đích của tôi: nếu có một phần API cần linh hoạt, nhưng bạn có thể bao gồm 80% trường hợp sử dụng với một số mặc định, hãy xem xét sử dụng các phương thức tĩnh trên giao diện của bạn. Do tính năng này không thường xuyên được sử dụng trong JDK, tôi sẽ rất thận trọng khi sử dụng nó trong mã của riêng tôi.

Các ví dụ của bạn không giống bất cứ thứ gì tôi thấy trong JDK. Đối với những trường hợp cụ thể đó, bạn gần như chắc chắn sẽ tạo ra một enumgiao diện thực hiện giao diện mong muốn. Một giao diện mô tả một tập hợp các hành vi và thực sự không có doanh nghiệp nào duy trì một bộ sưu tập các triển khai của nó.


-1

Tôi tự hỏi nếu có lý do để không sử dụng nó.

Làm thế nào về, um, tương thích với các JVM cũ?

Bạn có coi đây là một ý tưởng tốt nói chung?

Không. Đó là một sự thay đổi không tương thích ngược làm tăng thêm tính zilch cho tính biểu cảm của ngôn ngữ. Hai ngón tay cái xuống.

Có một số tình huống mô hình mà bạn mạnh mẽ đề xuất các lớp học?

Tôi thực sự khuyên bạn nên sử dụng các lớp để chứa chi tiết thực hiện. Một giao diện thực sự chỉ nhằm mục đích nói "Đối tượng này hỗ trợ các hoạt động XYZ" và điều đó không liên quan gì đến bất kỳ phương thức tĩnh nào bạn có thể nghĩ đến khi đưa vào khai báo giao diện. Tính năng này giống như một chiếc ghế tựa với tủ lạnh mini tích hợp. Chắc chắn rằng nó có một số cách sử dụng thích hợp nhưng nó không đủ sức nặng để xứng đáng là chủ đạo.

CẬP NHẬT: Xin vui lòng không downvote nữa. Rõ ràng một số người nghĩ rằng các phương thức tĩnh trong các giao diện là đầu gối của con ong và tôi đang hướng đến đây. Tôi sẽ sớm xóa câu trả lời này nhưng các bình luận kèm theo nó là một cuộc thảo luận thú vị.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
maple_shaft

Nếu tôi đánh giá thấp câu hỏi của bạn, tôi sẽ làm điều đó bởi vì hai câu trả lời đầu tiên của chúng tôi không phải là câu trả lời thực sự. Phiên bản mới của ngôn ngữ mang đến các công cụ mới để làm cho công cụ dễ dàng hơn, đó là mục đích chính của các phiên bản mới này. Câu trả lời thứ ba là hơi lạc lõng trong đống đổ nát của hai người đầu tiên.
Vlasec
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.