3 Stimmen

Ist es jemals in Ordnung, öffentliche Felder in Java zu verwenden?

Die Frage im Titel ist etwas allgemein und viele ähnliche Fragen wurden bereits beantwortet, sodass ich das allgemeine Bild verstehe. Hauptsächlich führt die Verwendung eines öffentlichen Feldes in einer Java-Klasse zu einer Abhängigkeit von den Implementierungsdetails der Klasse, was zu weniger wartbarem Software führt.

Trotzdem habe ich das Gefühl, dass ich sie irgendwie verwenden kann. Um dies zu erklären, werde ich ein Beispiel verwenden: Mit dem Aufkommen der funktionalen Schnittstellen von Java 8 kann ich endlich ein Ereignismodell verwenden, das mir gefällt, das ähnlich funktioniert wie Ereignisse in C# behandelt werden.

Das Ereignismodell ist in einem Paket implementiert, das als Drittanbieter-API in all meinen Projekten verwendet werden soll. Das sind die Hauptklassen:

EventArgs.java

public class EventArgs implements Serializable {
}

EventHandler.java

@FunctionalInterface
public interface EventHandler {
    void fire(Object sender, T args);
}

Event.java

public class Event {

    private final Set> handlers = new LinkedHashSet<>();

    public void addEventHandler(EventHandler handler) {
        handlers.add(handler);
    }

    public void removeEventHandler(EventHandler handler) {
        handlers.remove(handler);
    }

    public void fire(Object sender, T args) {
        for (EventHandler e : handlers) {
            e.fire(sender, args);
        }
    }
}

Was ich normalerweise in meinen Klassen machen möchte, die Ereignisse auslösen wollen, sieht so aus:

public class SomeClass {

    public final Event someEvent = new Event<>();

    public void someMethod() {
         // ...
         someEvent.fire();
    }
}

und in den Klassen, die das Ereignis abonnieren möchten:

public class SomeOtherClass {
    private SomeClass someInstance;

    public SomeOtherClass() {
        someInstance = new SomeClass();
        someInstance.someEvent.addEventHandler(this::someEventHandler);
    }

    private void someEventHandler(Object sender, SomeEventArgs args) {
         // mache etwas ...
    }
}

Für mich scheint das in Ordnung zu sein, weil ich keine Implementierungsdetails offenlege, tatsächlich ist das Ereignis Teil der Schnittstelle der Klasse. Liege ich damit völlig falsch? Sollte ich trotzdem einen Getter verwenden, um mit dem Ereignis zu interagieren?

Ein weiteres Beispiel, an das ich denken kann, ist ein Logger, der in der Klasse verwendet wird, aber von außen auf eine bestimmte Detailstufe gesetzt werden kann.

Also, um die Frage zu erweitern, ist es in Ordnung, einen öffentlichen Modifikator zu verwenden, wenn das Feld eine Drittanbieterkomponente ist, auf die zugegriffen werden kann, um ein bestimmtes Verhalten zu erreichen?

0voto

TheConstructor Punkte 4165

Es gibt einen Grund, warum Sie Felder öffentlich deklarieren können, aber abgesehen von einfachen Transportobjekten wie vielleicht einem zweidimensionalen Punkt, ... kann die Deklaration eines öffentlichen Feldes zu unerwarteten Ergebnissen führen.

Schauen wir uns SomeClass an und erweitern es zu SomeChildClass und SomeGrandChildClass wie folgt:

public class SomeChildClass extends SomeClass {

    public SomeChildClass() {
         super();
         someEvent.addEventHandler(...);
    }
}

und

public class SomeGrandChildClass extends SomeChildClass {

    public SomeGrandChildClass() {
         super();
         // Angenommen, FilteredEvent stellt sicher, dass ein Ereignis nur ausgelöst wird, wenn eine Bedingung erfüllt ist
         someEvent = new FilteredEvent();
    }
}

Was ist also passiert? Wir haben gerade einen EventHandler verloren aufgrund der Reihenfolge der Aufrufe zwischen Super-Konstruktoren und Konstruktor. Ich kann mir verschiedene Situationen vorstellen, in denen es sinnvoll erscheint, ein bestimmtes Event durch eine spezifische Implementierung von außen zu ersetzen (da das Feld öffentlich ist). Sie könnten natürlich public final verwenden, um Neuzuweisungen zu verhindern, aber dann verlieren Sie wiederum die Möglichkeit, das Verhalten in Unterklassen zu überschreiben.

Also ist die Event-Klasse in Ordnung für mich, aber die Implementierung der Methoden addSomeHandler und removeSomeHandler stellt sicher, dass Unterklassen ein anderes Ereignismanagement verwenden können und Eltern-Listener einschließen können, wenn sie auch die überschreibbaren Funktionen verwenden.

Ein weiteres Beispiel könnte eine Änderung des Ereignisbehandlungsmechanismus sein. Wenn Sie diese kurzen Methoden implementieren, können Sie sofort die alten Handler im alten Stil umhüllen, sie zusätzlichen Events zuweisen, ...

0voto

Hoopje Punkte 12398

Ja, grundsätzlich spricht nichts dagegen, öffentliche oder allgemein nicht-private Felder in Java zu haben. Dies wird von der Java-Sprache unterstützt und es gibt sicherlich Anwendungsfälle für sie. Trotzdem tendiere ich persönlich dazu, sie nur in nicht-öffentlichen, oft verschachtelten Hilfsklassen zu verwenden. In Klassen, die außerhalb ihrer Pakete verwendet werden sollen, möchte ich die Werte der Eigenschaften validieren oder dem Benutzer verbieten, Instanzen der Klasse zu ändern, Sammlungen in unveränderlichen Ansichten umhüllen, Standardwerte für Nullwerte einsetzen, usw. Und wenn ich das jetzt nicht möchte, möchte ich normalerweise in der Lage sein, sie später hinzuzufügen, ohne zu viel Code zu brechen. Also würde ich sagen: Nein, nicht-private Felder haben keinen Platz in Klassen, die zur öffentlichen Schnittstelle eines Pakets gehören.

In Ihrem speziellen Fall ist für mich ein Event ein Objekt, das die Informationen eines bestimmten Ereignisses kapselt, zum Beispiel eine einzelne Tastenbetätigung oder ein einzelner Mausklick, usw. Daher finde ich es seltsam, die Event-Listener im Event-Objekt selbst zu speichern, da dies bedeuten würde, dass die Event-Listener jedes Mal hinzugefügt werden müssen, wenn ein Ereignis eintritt. Für mich ist ein Event ein gutes Beispiel für eine Klasse, die wahrscheinlich nicht veränderbar sein sollte. Öffentliche Felder machen eine Instanz der Klasse sofort veränderbar, daher würde ich besonders davon abraten, öffentliche Felder im Event-Objekt zu verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X