Stały interfejs
W języku programowania Java wzorzec stałego interfejsu opisuje użycie interfejsu wyłącznie do definiowania stałych, a klasy implementują ten interfejs w celu uzyskania wygodnego dostępu składniowego do tych stałych. Ponieważ jednak stałe są bardzo często jedynie szczegółem implementacji, a interfejsy zaimplementowane przez klasę są częścią eksportowanego API, taka praktyka sprowadza się do umieszczania szczegółów implementacji w API, co zostało uznane za nieodpowiednie np. przez projektanta Javy, Joshuę Blocha . Ogólnie rzecz biorąc, gromadzenie stałych systemowych w klasy niezależne od zachowania może skutkować kiepskim zorientowanym obiektowo , ponieważ często jest to oznaką niskiej spójności . Z tych powodów stałe interfejsy można uznać za antywzorzec .
Użycie tego wzorca ma kilka innych wad: [ oryginalne badania? ]
- Zanieczyszcza przestrzeń nazw klas zmiennymi tylko do odczytu, które mogą nie być przydatne.
- W przeciwieństwie do taktycznej użyteczności implementacji stałego interfejsu w czasie kompilacji , przypadkowe artefakty w czasie wykonywania mają niewielki praktyczny cel (por. interfejsy znaczników , które również nie mają metod, ale są przydatne w czasie wykonywania).
- Jeśli w przyszłych wydaniach wymagana jest kompatybilność kodu binarnego, stały interfejs musi na zawsze pozostać interfejsem (nie można go przekształcić w klasę), nawet jeśli nie był używany jako interfejs w konwencjonalnym sensie .
- Bez IDE, które rozpoznaje, skąd pochodzą stałe, śledzenie ich z powrotem do zawierającej je klasy lub interfejsu może być czasochłonne.
- Instancja interfejsu nie jest składniowo bardziej użyteczna niż sama nazwa interfejsu (ponieważ nie ma metod).
- Jeśli programista nie sprawdzi zaimplementowanych interfejsów podczas dodawania stałej do klasy lub nie zrobi tego, ale zrobi literówkę w nazwie dodanej stałej, wartość stałej może zostać zmieniona po cichu. Rozważ przykład 2 poniżej.
Zauważ, że biblioteki Java same używają stałego wzorca interfejsu, co pokazuje, że w niektórych sytuacjach może to być rozsądny wybór.
Przykład 1
interfejs publiczny Stałe { double PI = 3,14159 ; podwójna PLANCK_CONSTANT = 6,62606896e-34 ; } public class Obliczenia implementuje Stałe { public double getReducedPlanckConstant () { return PLANCK_CONSTANT / ( 2 * PI ); } }
Przykład 2
interfejs publiczny Stałe { public static final int CONSTANT = 1 ; } public class Class1 implementuje Stałe { public static final int CONSTANT = 2 ; // * public static void main ( String args [] ) zgłasza wyjątek { System . na zewnątrz println ( STAŁA ); } }
Przed dodaniem wiersza oznaczonego gwiazdką uruchomienie Class1 drukuje 1. Po dodaniu wiersza Class1 drukuje 2. Obie wersje kompilują się bez ostrzeżeń i błędów.
Alternatywy
Wielu pułapek antywzorca można uniknąć, konwertując stały interfejs na klasę ze statycznymi atrybutami:
public final class Stałe { private Stałe () { // ograniczenie tworzenia instancji } public static final double PI = 3.14159 ; public static final double PLANCK_CONSTANT = 6.62606896e-34 ; }
Od wersji Java 5 można użyć importu statycznego , aby móc używać stałych bez kwalifikatora Constants:
importuj stałe stałe.PLANCK_CONSTANT ; importuj statyczne Stałe.PI ; obliczenia klasy publicznej { public double getReducedPlanckConstant () { return PLANCK_CONSTANT / ( 2 * PI ); } }
Stałe można również importować masowo za pomocą instrukcji import static Constants.* . Osiąga to te same cele, co użycie interfejsu, umożliwiając odwoływanie się do stałych bez kwalifikatora.
W różnym stopniu problemy wymienione powyżej zostały już rozwiązane:
- Ponieważ elementy statyczne można importować w określony sposób, przestrzeń nazw klas nie musi być zanieczyszczana wszystkimi elementami stałego interfejsu.
- Semantyka czasu wykonywania i kompilacji jest ściślej dopasowana w przypadku korzystania z importu statycznego zamiast stałych interfejsów.
- Skompilowany kod ma jedno ograniczenie kompatybilności binarnej mniej (to „obliczenia klasy implementują stałe”).
- Ponieważ importy statyczne dotyczą tylko bieżącego pliku (a nie całej hierarchii klas), łatwiej jest wykryć, gdzie zadeklarowano każdy statyczny element członkowski.
- Nie ma potrzeby deklarowania zmiennych o stałym typie interfejsu i jest potencjalnie jaśniejsze, że w rzeczywistości nie istnieje żadna konkretna instancja.
Należy jednak zauważyć, że zmiany nie poprawiają spójności klasy Constants ani nie zapobiegają przypadkowej cichej modyfikacji wartości stałej, więc import statyczny nie powinien być uważany za panaceum.