it-swarm.com.de

Ist es in Ordnung, wenn eine Klasse ihre eigene öffentliche Methode verwendet?

Hintergrund

Ich habe derzeit eine Situation, in der ich ein Objekt habe, das von einem Gerät sowohl gesendet als auch empfangen wird. Diese Nachricht hat mehrere Konstrukte wie folgt:

public void ReverseData()
public void ScheduleTransmission()

Die ScheduleTransmission -Methode benötigt , um die ReverseData -Methode bei jedem Aufruf aufzurufen. Es gibt jedoch Zeiten, in denen ich ReverseData extern aufrufen muss (und ich sollte vollständig außerhalb des Namespace hinzufügen), von wo aus das Objekt wird in der Anwendung instanziiert.

Was das "Empfangen" betrifft, meine ich, dass ReverseData in einem object_received - Ereignishandler extern aufgerufen wird, um die Daten rückgängig zu machen.

Frage

Ist es allgemein akzeptabel, dass ein Objekt seine eigenen öffentlichen Methoden aufruft?

24
Snoop

Ich würde sagen, dass dies nicht nur akzeptabel ist, sondern auch empfohlen wird, insbesondere wenn Sie Erweiterungen zulassen möchten. Um Erweiterungen der Klasse in C # zu unterstützen, müssen Sie die Methode gemäß den folgenden Kommentaren als virtuell kennzeichnen. Möglicherweise möchten Sie dies jedoch dokumentieren, damit sich jemand nicht wundert, wenn das Überschreiben von ReverseData () die Funktionsweise von ScheduleTransmission () ändert.

Es kommt wirklich auf das Design der Klasse an. ReverseData () klingt nach einem grundlegenden Verhalten Ihrer Klasse. Wenn Sie dieses Verhalten an anderen Stellen verwenden müssen, möchten Sie wahrscheinlich keine anderen Versionen davon haben. Sie müssen nur darauf achten, dass keine für ScheduleTransmission () spezifischen Details in ReverseData () gelangen. Das wird Probleme verursachen. Aber da Sie dies bereits außerhalb der Klasse verwenden, haben Sie das wahrscheinlich bereits durchdacht.

33
JimmyJames

Absolut.

Die Sichtbarkeit einer Methode dient ausschließlich dazu, den Zugriff auf eine Methode außerhalb der Klasse oder innerhalb einer untergeordneten Klasse zuzulassen oder zu verweigern. Öffentliche, geschützte und private Methoden können immer innerhalb der Klasse selbst aufgerufen werden.

Es ist nichts Falsches daran, öffentliche Methoden aufzurufen. Die Abbildung in Ihrer Frage ist das perfekte Beispiel für eine Situation, in der zwei öffentliche Methoden genau das sind, was Sie tun sollten.

Sie können jedoch sorgfältig auf die folgenden Muster achten:

  1. Eine Methode Hello() ruft World(string, int, int) wie folgt auf:

    Hello()
    {
        this.World("Some magic value here", 0, 100);
    }
    

    Vermeiden Sie dieses Muster. Verwenden Sie stattdessen optionale Argumente . Optionale Argumente erleichtern die Auffindbarkeit: Der Aufrufer, der Hello( Eingebt, weiß nicht unbedingt, dass es eine Methode gibt, mit der die Methode mit Standardwerten aufgerufen werden kann. Optionale Argumente sind ebenfalls selbstdokumentierend. World() zeigt dem Aufrufer nicht die tatsächlichen Standardwerte an.

  2. Eine Methode Hello(ComplexEntity) ruft World(string, int, int) wie folgt auf:

    Hello(ComplexEntity entity)
    {
        this.World(entity.Name, entity.Start, entity.Finish);
    }
    

    Verwenden Sie stattdessen Überladungen . Gleicher Grund: bessere Auffindbarkeit. Der Anrufer kann alle Überlastungen über IntelliSense sofort sehen und die richtige auswählen.

  3. Eine Methode ruft einfach andere öffentliche Methoden auf, ohne einen wesentlichen Wert hinzuzufügen.

    Denke nochmal nach. Benötigen Sie diese Methode wirklich? Oder sollten Sie es entfernen und den Anrufer die verschiedenen Methoden aufrufen lassen? Ein Hinweis: Wenn der Name der Methode nicht richtig erscheint oder schwer zu finden ist, sollten Sie ihn wahrscheinlich entfernen.

  4. Eine Methode validiert die Eingabe und ruft dann die andere Methode auf:

    Hello(string name, int start, int end)
    {
        if (name == null) throw new ArgumentNullException(...);
        if (start < 0) throw new OutOfRangeException(...);
        ...
        if (end < start) throw new ArgumentException(...);
    
        this.World(name, start, end);
    }
    

    Stattdessen sollte World seine Parameter selbst validieren oder privat sein.

20

Wenn etwas öffentlich ist, kann es jederzeit von jedem System aufgerufen werden. Es gibt keinen Grund, warum Sie nicht auch eines dieser Systeme sein können!

In hochoptimierten Bibliotheken möchten Sie die in Java.util.ArrayList#ensureCapacity(int) angegebene Redewendung kopieren.

stellen Sie sicher, dass die Kapazität

  • ensureCapacity ist öffentlich
  • ensureCapacity verfügt über alle erforderlichen Grenzwertprüfungen und Standardwerte usw.
  • ensureCapacity ruft ensureExplicitCapacity auf

sureCapacityInternal

  • ensureCapacityInternal ist privat
  • ensureCapacityInternal weist nur eine minimale Fehlerprüfung auf, da alle Eingaben aus der Klasse stammen
  • ensureCapacityInternal Ruft AUCH ensureExplicitCapacity auf

sureExplicitCapacity

  • ensureExplicitCapacity ist AUCH privat
  • ensureExplicitCapacity hat no Fehlerprüfung
  • ensureExplicitCapacity erledigt die eigentliche Arbeit
  • ensureExplicitCapacity wird nur von ensureCapacity und ensureCapacityInternal von irgendwoher aufgerufen

Auf diese Weise erhält Code, dem Sie vertrauen, privilegierten (und schnelleren!) Zugriff, da Sie wissen, dass seine Eingaben gut sind. Code, dem Sie nicht vertrauen, durchläuft eine gewisse Sorgfalt, um seine Integrität zu überprüfen und zu bombardieren oder Standardeinstellungen bereitzustellen oder auf andere Weise mit schlechten Eingaben umzugehen. Beide leiten zu dem Ort, der tatsächlich funktioniert.

Dies wird jedoch in ArrayList verwendet, einer der am häufigsten verwendeten Klassen im JDK. Es ist sehr wahrscheinlich, dass Ihr Fall nicht so komplex und streng ist. Kurz gesagt, wenn alle Aufrufe von ensureCapacityInternal durch Aufrufe von ensureCapacity ersetzt würden, wäre die Leistung immer noch sehr, sehr gut. Dies ist eine Mikrooptimierung, die wahrscheinlich erst nach eingehender Prüfung vorgenommen wird.

9
corsiKa

Es wurden bereits einige gute Antworten gegeben, und ich würde ihnen auch zustimmen, dass ein Objekt seine öffentlichen Methoden von seinen anderen Methoden aufrufen kann. Es gibt jedoch eine kleine Design-Einschränkung, auf die Sie achten müssen.

Öffentliche Methoden haben normalerweise den Vertrag, "das Objekt in einen konsistenten Zustand zu bringen, etwas Sinnvolles zu tun, das Objekt in einem (möglicherweise anderen) konsistenten Zustand zu belassen". Hier kann "konsistent" zum Beispiel bedeuten, dass das Length eines List<T> ist nicht größer als sein Capacity und das Verweisen auf die Elemente an Indizes von 0 bis Length-1 wird nicht werfen.

Innerhalb der Methoden des Objekts befindet sich das Objekt möglicherweise in einem inkonsistenten Zustand. Wenn Sie also eine Ihrer öffentlichen Methoden aufrufen, kann dies zu einer sehr falschen Aktion führen, da es nicht mit einer solchen Möglichkeit geschrieben wurde. Wenn Sie also vorhaben, Ihre öffentlichen Methoden von Ihren anderen Methoden aufzurufen, stellen Sie sicher, dass ihr Vertrag lautet: "Nehmen Sie das Objekt in einem bestimmten Zustand, tun Sie etwas Sinnvolles, lassen Sie das Objekt in einem (möglicherweise anderen) (möglicherweise inkonsistenten - aber nur dann, wenn die Initiale." Zustand war inkonsistent) Zustand ".

3
Joker_vD

Ein weiteres Beispiel für den Aufruf einer öffentlichen Methode innerhalb einer anderen öffentlichen Methode ist ein CanExecute/Execute-Ansatz. Ich benutze es, wenn ich beides brauche Validierung und invariante Erhaltung .

Aber im Allgemeinen bin ich immer vorsichtig. Wenn eine Methode a() innerhalb der Methode b() aufgerufen wird, bedeutet dies, dass die Methode a() ein Implementierungsdetail von b() ist. Sehr oft zeigt es an, dass sie zu verschiedenen Abstraktionsebenen gehören. Und die Tatsache, dass beide öffentlich sind, lässt mich fragen, ob es sich um eine Einzelverantwortungsprinzip Verletzung handelt oder nicht.

1
Zapadlo