Czy złą praktyką jest interfejs do definiowania stałych?


40

Piszę zestaw klas testowych junit w Javie. Istnieje kilka stałych, na przykład ciągi, których będę potrzebować w różnych klasach testowych. Myślę o interfejsie, który je definiuje i każda klasa testowa go zaimplementuje.

Korzyści, które tam widzę to:

  • łatwy dostęp do stałych: MY_CONSTANTzamiastThatClass.MY_CONSTANT
  • każda stała zdefiniowana tylko raz

Czy to podejście jest raczej dobrą czy złą praktyką? Mam ochotę trochę nadużyć koncepcji interfejsów.

Możesz ogólnie odpowiedzieć na temat interfejsów / stałych, ale także na temat testów jednostkowych, jeśli jest w tym coś wyjątkowego.


Odpowiedź na „Złą praktyką jest, aby interfejs definiował X?”, Ponieważ X jest czymkolwiek, co nie jest „sygnaturą metody”, prawie zawsze na pewno brzmi „Tak”.
T. Sar - Przywróć Monikę

Odpowiedzi:


79

Joshua Bloch odradza to w swojej książce Effective Java :

To, że klasa korzysta z niektórych stałych wewnętrznie, jest szczegółem implementacji. Implementacja stałego interfejsu powoduje wyciek tego szczegółu implementacji do eksportowanego interfejsu API. Dla użytkowników klasy nie ma znaczenia, że ​​klasa implementuje stały interfejs. W rzeczywistości może ich nawet pomylić. Co gorsza, stanowi zobowiązanie: jeśli w przyszłej wersji klasa zostanie zmodyfikowana, aby nie musiała już używać stałych, nadal musi implementować interfejs, aby zapewnić zgodność binarną.

Możesz uzyskać ten sam efekt z normalną klasą, która definiuje stałe, a następnie użyj import static com.example.Constants.*;


13

W naszym przypadku robimy to, ponieważ wartości stałych reprezentują kontrakt dla stanów końcowych, które musi zapewnić implementacja usługi. Umieszczenie tych stałych w interfejsie określa stany końcowe jako część kontraktu, a jeśli jakakolwiek implementacja interfejsu ich nie wykorzysta, nie wykona swojego zadania.

CZASAMI stałe są szczegółami implementacji. CZASAMI nie są. Jak zwykle inżynier musi użyć swojego mózgu, aby zdecydować, co robić, a nie polegać na szerokim schemacie lub praktyce.


7

Nie sądzę, że dobrze jest mieć interfejsy tylko dla stałych.

Ale jeśli interfejs definiujący zachowanie (metody implementujące klasy powinny implementować), ma stałe, to jest OK. Jeśli „wycieknie jakiś szczegół implementatora” do API, to właśnie tak powinno być. Nieszczelne są także to, że implementator implementuje metody foo i bar.

Weźmy na przykład interfejs java.awt.Transparency. Ma stałe OPAQUE, BITMASK i TRANSLUCENT, ale ma również metodę getTransparency ().

Jeśli projektant umieści tam te stałe, to dlatego, że pomyślał, że będzie wystarczająco stabilny, aby być częścią interfejsu, tak jak getTransparency ().


2

Pomyśl, że jest to punkt widzenia najbardziej popularny w miejscach, w których dominuje projektowanie na podstawie umowy.
Interfejsy to umowy. Umieszczenie stałych w interfejsach oznacza, że ​​każda klasa, która przestrzega umowy, zgadza się na wartość / koncepcję określoną przez stałą.


1
interfejsy to zamówienia publiczne. Stałe WARTOŚCI są prywatnymi sprawami, interfejs publiczny powinien co najwyżej ujawniać ich nazwy. Najlepiej zostaw to klasie abstrakcyjnej.
jwenting

Przypadki w punkcie: javax.naming.Context, javax.ims.Session i setki takich interfejsów ...
CMR

2
@jwenting Ponadto, czy interfejs publiczny może być wyświetlany "at most expose their names"bez ujawniania wartości?
CMR

to zależy od języka programowania. W przypadku Javy nie.
jwenting

2

Firma, w której pracowałem, intensywnie korzystała z 1 stałych importowanych przez interfejs . Nie wydaje mi się, żeby wynikało z tego jakaś szkoda.

Pytanie, które powinieneś sobie zadać, brzmi: jak ważna jest dla ciebie przestrzeń nazw? W przypadku stałych tak naprawdę wszystko działa jak klasa. Jeśli masz tysiące stałych, możesz nie chcieć, aby wszystkie były zawsze dostępne.

Fajną rzeczą w interfejsach jest to, że daje ci to korzyści z pracy w jedną stronę - weź wszystkie potrzebne przestrzenie nazw lub żaden z nich (i uzyskaj do nich bezpośredni dostęp MyInterface.CONSTANT). Prawie to samo import static MyInterface.*, ale nieco bardziej oczywiste.


1: Jeśli nie znasz Javy, nie mam na myśli tego importsłowa kluczowego, mam na myśli wprowadzone przezimplements MyConstantsInterface


1

Pochodzę z tła, na które największy wpływ mają przede wszystkim „sposób Ada” i „sposób .Net”. Powiedziałbym, że nie, że prawdopodobnie nie najlepiej jest deklarować stałe w interfejsach. Jest to technicznie niedozwolone w języku c #.

Powodem, dla którego mówię „nie”, jest to, że interfejs jest formą umowy, która określa zachowanie, a nie stan lub strukturę. Stała implikuje pewien rodzaj stanu (prymitywny) lub aspekt stanu (złożony lub agregowany).

Mogę docenić potrzebę udostępnienia wartości domyślnych i predefiniowanych wszystkim, którzy implementują interfejs, ale być może stan domyślny zostałby lepiej opisany w abstrakcyjnym lub wartościowym obiekcie lub szablonie, w którym wartości domyślne miałyby co najmniej minimalny kontekst.

Aby uzyskać bardziej techniczny przewodnik: download.oracle.com/javase/1.5.0/docs/guide/language/static-import.html


Dodanie kolejnych linków odnoszących się do importu statycznego (1.5): 1. Wikipedia 2. Dokumenty Oracle odwołujące się do @Justinc
Abhijeet

1
So when should you use static import? Very sparingly! Only use it when you'd otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes. If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Odniesienie z Oracle Docs
Abhijeet,

1

Nie, to nie jest ogólna zła praktyka.

Chodzi o to, że stałe, jak każdy inny artefakt, należy wprowadzić zgodnie z zasadami minimalnej widoczności i odpowiedniego poziomu abstrakcji.

Używanie składni tylko dlatego, że możesz, to prawdziwy problem.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.