Umieszczanie statycznych elementów w interfejsie (i implementowanie tego interfejsu) jest złą praktyką i istnieje nawet nazwa, Antipattern Constant Interface , patrz Efektywna Java , punkt 17:
Stały wzorzec interfejsu to słabe wykorzystanie interfejsów . To, że klasa używa wewnętrznie pewnych stałych, jest szczegółem implementacji. Implementacja stałego interfejsu powoduje wyciek szczegółów implementacji do wyeksportowanego interfejsu API klasy. Dla użytkowników klasy nie ma żadnego znaczenia, że klasa implementuje stały interfejs. W rzeczywistości może ich to nawet zmylić. Co gorsza, stanowi zobowiązanie: jeśli w przyszłej wersji klasa zostanie zmodyfikowana tak, aby nie musiała już używać stałych, nadal musi zaimplementować interfejs, aby zapewnić zgodność binarną. Jeśli klasa nie ostateczna implementuje stały interfejs, wszystkie jej podklasy będą miały swoje przestrzenie nazw zanieczyszczone stałymi w interfejsie.
Istnieje kilka stałych interfejsów w bibliotekach platformy Java, takich jak java.io.ObjectStreamConstants
. Te interfejsy powinny być traktowane jako anomalie i nie powinny być emulowane.
Aby uniknąć pułapek związanych ze stałym interfejsem (ponieważ nie można uniemożliwić ludziom jego implementacji), należy preferować odpowiednią klasę z prywatnym konstruktorem (przykład zapożyczony z Wikipedii ):
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
Aby uzyskać dostęp do stałych bez konieczności ich pełnej kwalifikacji (tj. Bez konieczności poprzedzania ich nazwą klasy), użyj importu statycznego (od wersji Java 5):
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations {
public double getReducedPlanckConstant() {
return PLANCK_CONSTANT / (2 * PI);
}
}
Ktokolwiek wymyślił tę hipotezę, niezależnie od tego, jakim był guru, wymyślił ją na podstawie potrzeby dalszego skutecznego wdrażania złych nawyków i praktyk. Hipoteza opiera się na promowaniu słuszności złych nawyków projektowania oprogramowania.
Napisałem odpowiedź obalającą tę hipotezę tutaj: Jaki jest najlepszy sposób implementacji stałych w Javie? wyjaśniając bezpodstawność tej hipotezy.
Pytanie to pozostawało otwarte przez 10 lat, aż zostało zamknięte w ciągu 2 godzin po tym, jak zamieściłem moje powody, które obalały tę hipotezę, w ten sposób narażając NIEWOLI do debaty tych, którzy mocno trzymają się tej błędnej hipotezy.
Oto punkty, które przedstawiłem przeciwko hipotezie
Podstawą do przyjęcia tej hipotezy jest potrzeba metod i OGRANICZAJĄCYCH reguł radzenia sobie ze skutkami złych nawyków i metodologii oprogramowania.
Zwolennicy sentymentu „ Ciągły wzorzec interfejsów to kiepskie wykorzystanie interfejsów” nie są w stanie podać żadnych innych powodów niż te spowodowane potrzebą radzenia sobie ze skutkami tych złych nawyków i praktyk.
Rozwiąż podstawowy problem.
Dlaczego więc nie w pełni wykorzystać i nie wykorzystać każdej funkcji językowej struktury języka Java dla własnej wygody. Nie są wymagane kurtki. Po co wymyślać zasady, które blokują Twój nieefektywny styl życia, aby dyskryminować i obciążać bardziej efektywny styl życia?
Podstawowa kwestia
jest organizacją informacyjną. Informacje pośredniczące w procesie oraz zachowanie tych informacji należy najpierw zrozumieć wraz z tzw. Regułami biznesowymi - przed inżynierią lub uzupełnieniem rozwiązań w procesie. Taki sposób organizacji informacji kilkadziesiąt lat temu nazwano normalizacją danych.
Wtedy możliwa jest tylko inżynieria rozwiązania, ponieważ dopasowanie ziarnistości i modularności składników rozwiązania z ziarnistością i modułowością składników informacji jest strategią optymalną.
Istnieją dwie lub trzy istotne przeszkody w organizowaniu informacji.
Brak postrzegania potrzeby „normalizacji” modelu danych.
Oświadczenia EF Codda dotyczące normalizacji danych są błędne, wadliwe i niejednoznaczne.
Najnowszą modą podszywającą się pod zwinną inżynierię jest błędne przekonanie, że nie należy planować i warunkować organizacji modułów z wyprzedzeniem, ponieważ można je modyfikować na bieżąco. Jako wymówkę używa się refaktoryzacji i ciągłych zmian bez przeszkadzania przez przyszłe odkrycia. Niezbędne są wtedy odkrycia zachowania informacji procesowych, przy użyciu sztuczek księgowych, aby opóźnić zyski i aktywizację, w związku z czym uważa się, że podstawowa wiedza i ich przetwarzanie nie są obecnie potrzebne.
Stosowanie stałych interfejsu jest dobrą praktyką.
Nie wymyślaj reguł ani nie wystawiaj na to fatwy tylko dlatego, że kochasz swoje nawyki programistyczne ad-hoc typu hit and run.
Nie zakazuj posiadania broni z tego powodu, że są ludzie, którzy albo nie wiedzą, jak obchodzić się z bronią, albo są skłonni do jej nadużywania.
Jeśli reguły, które wymyślisz, są przeznaczone dla początkujących programistów, którzy nie potrafią profesjonalnie kodować i zaliczasz się do nich, powiedz to - nie deklaruj swojej fatwy jako stosownej do odpowiednio znormalizowanych modeli danych.
Głupie rozumowanie - interfejsy nie były zamierzone przez flądry języka Java do używania w ten sposób?
Nie obchodzi mnie, jakie pierwotne intencje ojców założycieli mieli co do Konstytucji Stanów Zjednoczonych. Nie obchodzą mnie niepisane, nieskodyfikowane intencje. Dbam tylko o to, co jest dosłownie skodyfikowane w spisanej Konstytucji i jak mogę je wykorzystać do efektywnego funkcjonowania społeczeństwa.
Zależy mi tylko na tym, na co pozwalają mi specyfikacje języka / platformy Java i zamierzam je w pełni wykorzystać, aby zapewnić mi medium do wydajnego i skutecznego przedstawiania moich rozwiązań programowych. Nie są wymagane żadne kurtki.
Używanie stałych wyliczenia jest w rzeczywistości straszną praktyką.
Wymaga napisania dodatkowego kodu, aby odwzorować parametr na wartość. Fakt, że twórcy Javy nie zapewnili mapowania wartości parametrów bez twojego napisania, że kod mapujący pokazuje, że Stałe Enum są równie niezamierzonym użyciem języka Java.
Zwłaszcza, że nie jest się zachęcanym do normalizowania i komponowania parametrów, można by odnieść fałszywe wrażenie, że parametry zmieszane w torebce Enum należą do tego samego wymiaru.
Stałe to API Contract
Nie zapomnij o tym. Jeśli zaprojektowałeś i znormalizowałeś swój model danych i zawiera on stałe, wtedy te stałe są kontraktami. Jeśli nie znormalizowałeś swojego modelu danych, powinieneś zastosować się do podanych przez Ciebie fatwy, jak praktykować restrykcyjne kodowanie, aby poradzić sobie z tym złym nawykiem.
Dlatego interfejsy są doskonałym sposobem implementacji kontraktu Constants.
Dziwne domniemanie - co się stanie, jeśli interfejs zostanie nieumyślnie zaimplementowany.
Tak. Każdy może nieumyślnie zaimplementować dowolny interfejs. Nic nie stanie na przeszkodzie takim przypadkowym programistom.
Zaprojektuj i znormalizuj swój model danych pod kątem wycieków
Nie wprowadzaj restrykcyjnych dekretów, aby chronić domniemane złe praktyki, które powodują wyciek niezakontraktowanych / zbłąkanych parametrów do API. Rozwiąż podstawowy problem, zamiast przypisywać winę stałym interfejsu.
Nie używanie IDE jest złą praktyką
Normalnie działający i SKUTECZNY programista nie jest obecny, aby udowodnić, jak długo może przebywać pod wodą, jak daleko może przejść w piekielnym upale lub mokrej burzy. Ma używać wydajnego narzędzia, takiego jak samochód, autobus lub przynajmniej rower, aby codziennie zabierać ją do pracy 10 mil.
Nie nakładaj ograniczeń na innych programistów tylko dlatego, że masz obsesję na punkcie ezoterycznej ascezy programowania bez IDE.
Kilka frameworków ma pomóc programistom efektywnie praktykować złe nawyki.
OSGI jest takim szkieletem. Tak samo jest z dekretem dotyczącym stałych interfejsu.
Dlatego ostateczna odpowiedź ...
Stałe interfejsu są skutecznym i wydajnym sposobem umieszczania w kontraktach dobrze zaprojektowanych i znormalizowanych komponentów modelu danych.
Stałe interfejsu w odpowiednio nazwanym interfejsie prywatnym zagnieżdżonym w pliku klasy to również dobra praktyka polegająca na grupowaniu wszystkich prywatnych stałych zamiast rozpraszania ich po całym pliku.
źródło
Kilka razy natknąłem się na to stare pytanie, a przyjęta odpowiedź wciąż mnie dezorientuje. Po długim namyśle myślę, że to pytanie można dalej wyjaśnić.
Dlaczego warto używać stałej interfejsu?
Wystarczy je porównać:
vs
To samo użycie. Znacznie mniej kodu.
Zła praktyka?
Myślę, że odpowiedź @Pascal Thivent ma niewłaściwy nacisk, oto moja wersja:
Cytat z Effective Java zakłada, że interfejs jest implementowany przez innych, co moim zdaniem nie powinno (i nie będzie).
Kiedy tworzysz stały interfejs o nazwie podobnej
Constants
, nikt nie powinien go implementować. (choć technicznie możliwe, co jest jedynym problemem tutaj)To się nie stanie w standardowej bibliotece
Biblioteka standardowa nie może pozwolić sobie na jakiekolwiek możliwe niewłaściwe wykorzystanie projektu, więc po prostu go tam nie zobaczysz.
Jednakże , dla normalnych codziennych projektów, programistów wykorzystujących interfejs stałych jest o wiele łatwiejsze, ponieważ nie musisz się martwić
static
,final
,empty constructor
, etc, i to nie spowoduje żadnego problemu złego projektu. Jedynym minusem, o jakim przychodzi mi do głowy, jest to, że nadal ma nazwę „interfejs”, ale nic poza tym.Niekończąca się debata
Na koniec myślę, że wszyscy po prostu cytują z książek, opiniują i uzasadniają swoje stanowiska. Nie ma dla mnie wyjątku. Może decyzja nadal należy do twórców każdego projektu. Po prostu użyj go, jeśli czujesz się komfortowo. Najlepsze, co możemy zrobić, to zapewnić spójność w całym projekcie .
źródło
public
można również pominąć, ponieważ jest to interfejs, dzięki czemu jest po prostu.double PI = 3.14159;
UżycieConstants.PI
nie potrzebuje klasy używającej tego do zaimplementowaniaConstants
interfejsu! Myślę, że podejście do interfejsu jest znacznie czystsze pod względem użytkowania, IMHOJoshua Bloch, „Effective Java - Programming Language Guide”:
źródło
Są przydatne, jeśli masz wspólne stałe, które będą używane w klasach implementujących interfejs.
Oto przykład: http://www.javapractices.com/topic/TopicAction.do?Id=32
Należy jednak pamiętać, że zalecaną praktyką jest używanie statycznych importów zamiast stałych w interfejsach. Oto odniesienie: http://www.javapractices.com/topic/TopicAction.do?Id=195
źródło
Są odpowiedzi, które są bardzo rozsądne.
Ale mam pewne przemyślenia na ten temat. (może się mylić)
Moim zdaniem pola w interfejsie nie powinny być stałymi dla całego projektu, są jedynie środkami dla interfejsu, a interfejsy go rozszerzają i klasy, które te interfejsy implementują lub mają z nimi ścisły związek. Powinny być używane w pewnym zakresie, a nie globalnym.
źródło
Dwie kwestie dotyczące interfejsu:
Interfejs opisuje podzbiór tego, co może zrobić obiekt, który go implementuje. (To jest intuicja)
Interfejs opisuje wspólne stałe, po których następują obiekty, które go implementują.
Więc myślę, że jeśli Constants Interface nie jest używany do globalnych stałych , to jest to dopuszczalne:
implements
ją (i oczywiście użyj tych wspólnych stałych w implementacji).Przykład:
W tym przykładzie:
Circle implements Drawable
, od razu wiesz, żeCircle
prawdopodobnie jest zgodny ze stałymi zdefiniowanymi wDrawable
, w przeciwnym razie będą musieli wybrać gorszą nazwę od dobrychPI
iGOLDEN_RATIO
już została zajęta!Drawable
obiekty są zgodne ze specyfikąPI
iGOLDEN_RATIO
zdefiniowane wDrawable
, mogą istnieć obiekty, które nieDrawable
mają różnej precyzji pi i złotego podziału.źródło
javax.swing.SwingConstants
Interfejs jest przykładem, który dostał pól statycznych, które są wykorzystywane w klasach skrzydłowych. Pozwala to na łatwe użycie czegoś takiego jakthis.add(LINE_START, swingcomponent);
this.add(this.LINE_START, swingcomponent);
lubthis.add(SwingComponents.LINE_START, swingcomponent);
Jednak ten interfejs nie ma metod ...
źródło
Natknąłem się na to pytanie i pomyślałem, że dodam coś, o czym nie było mowy. Ogólnie rzecz biorąc, zgadzam się z odpowiedzią Pascala tutaj . Jednak nie sądzę, aby stałe na interfejsie były „zawsze” antywzorem.
Na przykład, jeśli definiowane przez Ciebie stałe są częścią kontraktu dla tego interfejsu, myślę, że interfejs jest doskonałym miejscem na stałe. W niektórych przypadkach prywatna weryfikacja parametrów bez ujawniania umowy użytkownikom implementacji nie jest odpowiednia. Bez publicznego kontraktu użytkownicy mogą tylko zgadywać, z czym walidujesz, bez dekompilacji klasy i czytania kodu.
Jeśli więc zaimplementujesz interfejs, a interfejs ma stałe, których używasz, aby zapewnić swoje kontrakty (na przykład zakresy liczb całkowitych), wówczas użytkownik Twojej klasy może być pewien, że używa instancji interfejsu poprawnie, sprawdzając stałe w interfejsie sami. Byłoby to niemożliwe, gdyby stałe były prywatne dla twojej implementacji lub twoja implementacja była pakietem prywatnym lub coś w tym rodzaju.
źródło
Używam stałych interfejsu, gdy mam do czynienia ze stałymi współdzielonymi między klasami.
Grupowanie jest ogromnym atutem, szczególnie przy dużym zestawie stałych.
Aby użyć, po prostu połącz je ze sobą:
źródło
Źródło: Styl kodowania narzędzi programistycznych Java
źródło