Interface als Konstantensammler

Hallo.

Ich habe auf einer seite gelesen, es sei total falsch ein Interface als „Konstantensammler“ zu benutzen.
Das ist der Text:

Nun ja, einige zeit später (heute) stöbere ich wieder ein bisschen im freigegeben java source rum,
und finde das hier:

spoilern ist kacke! :smiley:
[spoiler]

 * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package javax.swing;


/**
 * A collection of constants generally used for positioning and orienting
 * components on the screen.
 *
 * @author Jeff Dinkins
 * @author Ralph Kar (orientation support)
 */
public interface SwingConstants {

        /**
         * The central position in an area. Used for
         * both compass-direction constants (NORTH, etc.)
         * and box-orientation constants (TOP, etc.).
         */
        public static final int CENTER  = 0;

        //
        // Box-orientation constant used to specify locations in a box.
        //
        /**
         * Box-orientation constant used to specify the top of a box.
         */
        public static final int TOP     = 1;
        /**
         * Box-orientation constant used to specify the left side of a box.
         */
        public static final int LEFT    = 2;
        /**
         * Box-orientation constant used to specify the bottom of a box.
         */
        public static final int BOTTOM  = 3;
        /**
         * Box-orientation constant used to specify the right side of a box.
         */
        public static final int RIGHT   = 4;

        //
        // Compass-direction constants used to specify a position.
        //
        /**
         * Compass-direction North (up).
         */
        public static final int NORTH      = 1;
        /**
         * Compass-direction north-east (upper right).
         */
        public static final int NORTH_EAST = 2;
        /**
         * Compass-direction east (right).
         */
        public static final int EAST       = 3;
        /**
         * Compass-direction south-east (lower right).
         */
        public static final int SOUTH_EAST = 4;
        /**
         * Compass-direction south (down).
         */
        public static final int SOUTH      = 5;
        /**
         * Compass-direction south-west (lower left).
         */
        public static final int SOUTH_WEST = 6;
        /**
         * Compass-direction west (left).
         */
        public static final int WEST       = 7;
        /**
         * Compass-direction north west (upper left).
         */
        public static final int NORTH_WEST = 8;

        //
        // These constants specify a horizontal or
        // vertical orientation. For example, they are
        // used by scrollbars and sliders.
        //
        /** Horizontal orientation. Used for scrollbars and sliders. */
        public static final int HORIZONTAL = 0;
        /** Vertical orientation. Used for scrollbars and sliders. */
        public static final int VERTICAL   = 1;

        //
        // Constants for orientation support, since some languages are
        // left-to-right oriented and some are right-to-left oriented.
        // This orientation is currently used by buttons and labels.
        //
        /**
         * Identifies the leading edge of text for use with left-to-right
         * and right-to-left languages. Used by buttons and labels.
         */
        public static final int LEADING  = 10;
        /**
         * Identifies the trailing edge of text for use with left-to-right
         * and right-to-left languages. Used by buttons and labels.
         */
        public static final int TRAILING = 11;
        /**
         * Identifies the next direction in a sequence.
         *
         * @since 1.4
         */
        public static final int NEXT = 12;

        /**
         * Identifies the previous direction in a sequence.
         *
         * @since 1.4
         */
        public static final int PREVIOUS = 13;
}

[/spoiler]

Ist das dann nicht genau ein beispiel für einen missbrauch?
Und das von leuten die java selbst programmieren?
Oder ist es eben in manchen fällen doch nicht so schlimm?

OFFTOPIC: An die admins hier - byte welt hier ist auf einmal auf englisch. Ist zwar nicht schlimm, aber ich wollt fragen ob es einfach
ein bug ist oder ob es einfach nur so ist…

Richtig.

Genau von den selben!

Schlimm ist es so oder so nicht. Hässlich ist IMO der richtige Begriff. Man geht an der semantischen Bedeutung eines Interfaces vorbei.

Aber der eigentliche Grund wird viel mehr der sein:

Enums sind allerdings erst seit Java-Version 1.5 verfügbar. (Siehe auch Feature-List von Java 1.5)

Wie gesagt hässlich. Allerdings muss ich auch zugeben, dass ich das auch schon mal „verbrochen“ habe.

[quote=mymaksimus]OFFTOPIC: An die admins hier - byte welt hier ist auf einmal auf englisch. Ist zwar nicht schlimm, aber ich wollt fragen ob es einfach
ein bug ist oder ob es einfach nur so ist…[/quote]
Bei mir ist alles noch auf Deutsch. Du kannst das aber selbst einstellen in deinem Benutzerkonto:
http://forum.byte-welt.net/profile.php?do=editoptions
Siehe “Sprache der Benutzeroberfläche”.

[quote=mymaksimus]OFFTOPIC: An die admins hier - byte welt hier ist auf einmal auf englisch. Ist zwar nicht schlimm, aber ich wollt fragen ob es einfach
ein bug ist oder ob es einfach nur so ist…[/quote]

Ist bei mir nicht so. Solche Anmerkungen solltest du zukünftig aber besser nicht in einem anderen Thema verstecken sondern im entsprechenden Forum posten. Sollte bei dir das Forum in englisch sein, so hast du es vllt darauf eingestellt. Wenn du komplett nach unten scrollst solltest du 2 Dropdowns sehen. Bei dem linken kannst du das Theme einstellen, bei dem rechts daneben die Sprache. Möglicherweise hast du da (ausversehen) die Sprache umgestellt.

Ganz unten links kann man die Sprache umstellen.

Ansosnten hat man mit Java 5 ein paar Dinge eingefuehrt, die das “Constant Interface Anti Pattern” ueberfluessig macht, static imports und enums.

Ja sry, es ist mir nach dem abschicken so aufgefallen. Trozdem danke

Um nochmal zum Thema zurueck zukommen - Schlingel hat eigentlich schon alles gesagt.

Allgemein sollte man Abstand nehmen Java™ sourcen als beleg fuer eine Argumentation nehmen. Man macht dabei immer die falsche Annahme, dass die Entwickler dort alles richtig gemacht haben und so den Standart definiert haben…

Das Schlimme an diesem Antipattern ist nicht so sehr, Konstanten in ein Interface zu packen (auch wenn eine finale, nicht instanziierbare Klasse oder ein Enum ohne Instanzen meiner Meinung nach die bessere Wahl ist), sondern von diesem Interface zu erben, nur um an die Konstanten zu kommen. Ein Interface soll eigentlich ein bestimmtes Verhalten bzw. das Vorhandensein einer bestimmten API dokumentieren, und das ist hier nicht der Fall. Es wird die Regel “Composition over Inheritance” verletzt und ein eigentlich “unnötiges” Interface wird Teil der öffentlichen API, und das ist der eigentliche “Mißbrauch”. Seit es statische Imports gibt, gibt es nicht mal mehr die Ausrede, mit diesem Hack ein paar Tastendrücke sparen zu können.

Nebenbei bemerkt wirst du noch ganz andere Verbrechen in den Java-Bibliotheken finden, z.B. Verletzungen des equals-hashcode-compareTo-Kontrakts, oder Mißgeburten wie java.util.Date.

[QUOTE=Landei]Das Schlimme an diesem Antipattern ist nicht so sehr, Konstanten in ein Interface zu packen (auch wenn eine finale, nicht instanziierbare Klasse oder ein Enum ohne Instanzen meiner Meinung nach die bessere Wahl ist), sondern von diesem Interface zu erben, nur um an die Konstanten zu kommen. Ein Interface soll eigentlich ein bestimmtes Verhalten bzw. das Vorhandensein einer bestimmten API dokumentieren, und das ist hier nicht der Fall. Es wird die Regel “Composition over Inheritance” verletzt und ein eigentlich “unnötiges” Interface wird Teil der öffentlichen API, und das ist der eigentliche “Mißbrauch”. Seit es statische Imports gibt, gibt es nicht mal mehr die Ausrede, mit diesem Hack ein paar Tastendrücke sparen zu können.

Nebenbei bemerkt wirst du noch ganz andere Verbrechen in den Java-Bibliotheken finden, z.B. Verletzungen des equals-hashcode-compareTo-Kontrakts, oder Mißgeburten wie java.util.Date.[/QUOTE]

Das mit dem nur implementieren (das meinst du, oder?) ist mir klar.
Was genau sind statische imports, an diese stelle mal so dahingefragt? (ja ich kann auch googeln, aber wenn man grad so davon spricht…)

Was genau hat es denn mit java.util.date auf sich? Ich glaube ich hab das sogar schon einmal benutzt…

Mal so ne Frage, waere es ‘ok’ das interface package private zu halten damit man die Klassr die es impl. etwas aufraeunmmt?

Sent from my LT22i using Tapatalk now Free

[QUOTE=groggy]Mal so ne Frage, waere es ‚ok‘ das interface package private zu halten damit man die Klassr die es impl. etwas aufraeunmmt?
[/quote]
Interfaces sind meist sinnfrei wenn sie nicht public sind.
Implementirungen koennten package private sein.
Was geht, ist ein nested Interface in eine Klasse zu packen, dann waere das Interface zB. private.

Sent from my LT22i using Tapatalk now Free

Das ist ja interessant gaehn :wink:

Das wird automatisch eingefügt… :slight_smile:

Ja und mit ein bisschen Bemuehen koennte man das auch ausschalten und andere nicht damit nerven (gab aber dazu im alten Forum schon ein Diskussion)

K dann pack ich halt alle wariablen in die klasse

Sent from my LT22i using Tapatalk now Free

[QUOTE=Landei]Das Schlimme an diesem Antipattern ist nicht so sehr, Konstanten in ein Interface zu packen (auch wenn eine finale, nicht instanziierbare Klasse oder ein Enum ohne Instanzen meiner Meinung nach die bessere Wahl ist), sondern von diesem Interface zu erben, nur um an die Konstanten zu kommen. Ein Interface soll eigentlich ein bestimmtes Verhalten bzw. das Vorhandensein einer bestimmten API dokumentieren, und das ist hier nicht der Fall. Es wird die Regel “Composition over Inheritance” verletzt und ein eigentlich “unnötiges” Interface wird Teil der öffentlichen API, und das ist der eigentliche “Mißbrauch”. Seit es statische Imports gibt, gibt es nicht mal mehr die Ausrede, mit diesem Hack ein paar Tastendrücke sparen zu können.

Nebenbei bemerkt wirst du noch ganz andere Verbrechen in den Java-Bibliotheken finden, z.B. Verletzungen des equals-hashcode-compareTo-Kontrakts, oder Mißgeburten wie java.util.Date.[/QUOTE]Okay, bei java.util.Date bin ich nicht sicher, aber in der API gibt es duraus Dinge, die man wegen der Abwärtskompatibilität beibehalten und deswegen in Folgeversionen auch fortgesetzt hat und auch noch weiter fortsetzt.

Zum Thema: Das was du da machen willst, geht auch mit absrtakten Klassen und einem privaten Konstruktor. Dabei fällt allerdings aus, dass man eine solche implementieren kann und so nutzt man es halt per statischen Import. Solche Klassen bieten dann auch noch den “Vorteil” als Utility-Klassen umgebaut werden zu können.

[QUOTE=mymaksimus]Das mit dem nur implementieren (das meinst du, oder?) ist mir klar.
Was genau sind statische imports, an diese stelle mal so dahingefragt? (ja ich kann auch googeln, aber wenn man grad so davon spricht…)[/quote]

Wenn du eine statische Methode wie Math.max() oder ein statisches Feld wie Math.PI oder ein Enum hast, schreibst du normalerweise:

import java.util.Math; //OK, bräuchte man für java.lang-Klassen jetzt nicht, ist ja nur ein Beispiel
import java.nio.file.AccessMode; //ein Enum
...
double z = Math.max(x,y);
double tau = 2*Math.PI;
AccessMode mode = AccessMode.READ;

Ein statischer Import wäre:

import static java.util.Math.max; 
import static java.util.Math.PI; 
import static java.nio.file.AccessMode.*
...
double z = max(x,y);
double tau = 2*PI;
AccessMode mode = READ;

Was genau hat es denn mit java.util.date auf sich? Ich glaube ich hab das sogar schon einmal benutzt…

Der schlimmste Fehler ist, dass Date veränderlich ist. Eigentlich müsstest du in jedem Setter und Getter(!) für Date eine Kopie erstellen, damit es dir der Client-Code nicht heimlich ändert. Ich kenne auch die Empfehlung, stattdessen intern long zu verwenden, und immer umzuwandeln. Ansonsten ist die API grauenhaft. Z.B. gibt es wohl keinen Entwickler, der nicht einmal über die null-basierten Monate (Januar ist 0, Februar ist 1…) oder die 1900-basierten Jahre (2013 ist Jahr 113) gestolpert ist, auch wenn das inzwischen alles deprecated ist - und man stattdessen umständlich mit Calendar hantieren soll. Dann gibt es weitere Probleme mit „Familienangehörigen“, z.B. ist die Sortierung mit der Unterklasse Timestamp nicht konsistent (weil Timestamp genauer ist, das in Date.compareTo aber nicht berücksichtigt wird). Und das sind nur die gröbsten Schnitzer.

Als JAVA Noob sehe ich ein, dass in ein Interface keine Konstanten reingehören. Wo würdet ihr denn sagen gehören sie dann hin?

Ich sehe bei Kollegen oft, dass sie mit Konstanten Startparameter für die Applikation festlegen. Persönlich finde ich das nicht so schön, ein Parameter ist eben nicht konstant und deswegen eben keine Konstante. Ich lege meine Konstanten (wenn sie denn welche sind) immer dort ab, wo sie ein anderer Entwickler suchen würde, also zB Konstanten für eine DB-Klasse eben in die DB-Klasse, und entscheide dabei auch gleich ob sie public sind oder nicht. Ist das gut so?

[QUOTE=xote]Als JAVA Noob sehe ich ein, dass in ein Interface keine Konstanten reingehören. Wo würdet ihr denn sagen gehören sie dann hin?

Ich sehe bei Kollegen oft, dass sie mit Konstanten Startparameter für die Applikation festlegen. Persönlich finde ich das nicht so schön, ein Parameter ist eben nicht konstant und deswegen eben keine Konstante. Ich lege meine Konstanten (wenn sie denn welche sind) immer dort ab, wo sie ein anderer Entwickler suchen würde, also zB Konstanten für eine DB-Klasse eben in die DB-Klasse, und entscheide dabei auch gleich ob sie public sind oder nicht. Ist das gut so?[/QUOTE]Also nirgendwo steht, dass Interfaces keine Konstanten haben dürfen, nur dass man sie als ConstantPool missbraucht ist halt ein Antipattern. Wo man öffentliche Konstanten sonst noch so hinpacken kann, steht oben. Nicht öffentliche Konstanten gehören dann logischerweise in die Klasse, die sie benötigen.

Ein guter Platz für “Konstanten” (die in der Realität ja nicht immer so konstant sind) ist die Konfigurationsdatei eines Dependency-Injection-Frameworks (bzw. eine Property-Datei, die davon ausgelesen wird). Für eine Client-Klasse sieht es dann so aus, als ob die Konstante “magisch” irgendwoher kommt, z.B. mit Spring:

public class Foo {
    @Autowired         
    private Bar bar; //ist einfach "da", wenn das DI-Framework richtig konfiguriert wurde
 
    @Value("${wichtiger.string}")
    private String wichtigerString;  //wichtiger String aus einer Property-Datei
    
    ...
}

Oder für Guice: http://stackoverflow.com/questions/3071891/guice-and-properties-files