it-swarm-eu.dev

Wann sollten Sie eine private / innere Klasse verwenden?

Zur Verdeutlichung frage ich nach

public class A{
    private/*or public*/ B b;
}

vs.

public class A{
    private/*or public*/ class B{
        ....
    }
}

Ich kann mir definitiv einige Gründe vorstellen, den einen oder anderen zu verwenden, aber was ich wirklich gerne sehen würde, sind überzeugende Beispiele, die zeigen, dass die Vor- und Nachteile nicht nur akademisch sind.

21
EpsilonVector

Sie werden normalerweise verwendet, wenn eine Klasse ein internes Implementierungsdetail einer anderen Klasse ist und nicht Teil ihrer externen Schnittstelle. Ich habe sie meistens als reine Datenklassen gesehen, die die internen Datenstrukturen in Sprachen sauberer machen, die keine separate Syntax für Strukturen im C-Stil haben. Sie sind manchmal auch nützlich für stark angepasste, von einer Methode abgeleitete Objekte wie Ereignishandler oder Arbeitsthreads.

20
Karl Bielefeldt

Angenommen, Sie erstellen einen Baum, eine Liste, ein Diagramm usw. Warum sollten Sie die internen Details eines Knotens oder einer Zelle der Außenwelt aussetzen?

Jeder, der ein Diagramm oder eine Liste verwendet, sollte sich nur auf seine Schnittstelle verlassen, nicht auf seine Implementierung, da Sie sie möglicherweise eines Tages in der Zukunft ändern möchten (z. B. von einer Array-basierten Implementierung zu einer zeigerbasierten) und auf die Clients, die Ihre verwenden Die Datenstruktur (jeder von ihnen) müsste ihren Code ändern, um ihn an die neue Implementierung anzupassen.

Wenn Sie stattdessen die Implementierung eines Knotens oder einer Zelle in eine private innere Klasse kapseln, können Sie die Implementierung jederzeit ändern, ohne dass die Clients gezwungen sind, ihren Code entsprechend anzupassen, solange die Schnittstelle Ihrer Datenstruktur erhalten bleibt unberührt.

Das Ausblenden der Details der Implementierung Ihrer Datenstruktur führt auch zu Sicherheitsvorteilen. Wenn Sie Ihre Klasse verteilen möchten, stellen Sie nur die Schnittstellendatei zusammen mit der kompilierten Implementierungsdatei zur Verfügung, und niemand weiß, ob Sie tatsächlich Arrays oder Zeiger verwenden für Ihre Implementierung, um Ihre Anwendung vor jeglicher Ausnutzung oder zumindest vor Wissen zu schützen, da Ihr Code nicht missbraucht oder überprüft werden kann. Unterschätzen Sie bitte nicht die Tatsache, dass es sich in solchen Fällen um eine äußerst elegante Lösung handelt.

9
Nicola Lamonaca

Meiner Meinung nach ist es ein fairer Cop, intern definierte Klassen für Klassen zu verwenden, die kurz in einer Klasse verwendet werden, um eine bestimmte Aufgabe zu ermöglichen.

Wenn Sie beispielsweise eine Liste von Daten binden müssen, die aus zwei nicht verwandten Klassen bestehen:

public class UiLayer
{
    public BindLists(List<A> as, List<B> bs)
    {
        var list = as.ZipWith(bs, (x, y) => new LayerListItem { AnA = x, AB = y});
        // do stuff with your new list.
    }

    private class LayerListItem
    {
        public A AnA;
        public B AB;
    }
}

Wenn Ihre interne Klasse von einer anderen Klasse verwendet wird, sollten Sie sie separat platzieren. Wenn Ihre interne Klasse eine Logik enthält, sollten Sie diese separat platzieren.

Grundsätzlich denke ich, dass sie sich hervorragend zum Verstopfen von Löchern in Ihren Datenobjekten eignen, aber sie sind schwer zu pflegen, wenn sie tatsächlich Logik enthalten müssen, da Sie wissen müssen, wo Sie nach ihnen suchen müssen, wenn Sie sie ändern müssen.

5
Ed James
  • Innere Klassen in einer bestimmten Sprache (z. B. Java) sind an ein Objekt ihrer enthaltenden Klasse gebunden und können ihre Mitglieder verwenden, ohne sie zu qualifizieren. Wenn verfügbar, ist es klarer, als sie mithilfe anderer Sprachfunktionen erneut zu implementieren.

  • Verschachtelte Klassen in einer anderen Sprache (z. B. C++) haben keine solche Bindung. Sie verwenden einfach die von der Klasse bereitgestellte Gültigkeitsbereichs- und Barrierefreiheitskontrolle.

4
AProgrammer

Ich vermeide innere Klassen in Java, weil Hot-Swapping bei Vorhandensein innerer Klassen nicht funktioniert. Ich hasse das, weil ich es wirklich hasse, den Code für solche Überlegungen zu kompromittieren, aber diese Tomcat-Neustarts fügen hinzu oben.

3
kevin cline

Eine der Anwendungen für private statische innere Klassen ist das Memo-Muster. Sie fügen alle Daten, die gespeichert werden müssen, in eine private Klasse ein und geben sie von einer Funktion als Objekt zurück. Niemand außerhalb kann es nicht (ohne Reflexion, Deserialisierung, Speicherinspektion ...) untersuchen/modifizieren, aber er kann es Ihrer Klasse zurückgeben und es kann seinen Zustand wiederherstellen.

2
user470365

Ein Grund für die Verwendung einer privaten inneren Klasse könnte sein, dass eine von Ihnen verwendete API die Vererbung einer bestimmten Klasse erfordert, Sie das Wissen dieser Klasse jedoch nicht an Benutzer Ihrer äußeren Klasse exportieren möchten. Zum Beispiel:

// async_op.h -- someone else's api.
struct callback
{
    virtual ~callback(){}
    virtual void fire() = 0;
};

void do_my_async_op(callback *p);



// caller.cpp -- my api
class caller
{
private :
    struct caller_inner : callback
    {
        caller_inner(caller &self) : self_(self) {}
        void fire() { self_.do_callback(); }
        caller &self_;
    };

    void do_callback()
    {
        // Real callback
    }

    caller_inner inner_;

public :
    caller() : inner_(*this) {}

    void do_op()
    {
        do_my_async_op(&inner_);
    }
};

In diesem Fall muss für do_my_async_op ein Objekt vom Typ Rückruf übergeben werden. Dieser Rückruf hat eine public Member-Funktionssignatur, die von der API verwendet wird.

Wenn do_op () von der Outer_class aufgerufen wird, wird anstelle eines Zeigers auf sich selbst eine Instanz der privaten inneren Klasse verwendet, die von der erforderlichen Callback-Klasse erbt. Die äußere Klasse hat einen Verweis auf die äußere Klasse, um den Rückruf einfach in die Mitgliedsfunktion privat do_callback der äußeren Klasse zu verschieben.

Dies hat den Vorteil, dass Sie sicher sind, dass niemand sonst die öffentliche Mitgliedsfunktion "fire ()" aufrufen kann.

2
Kaz Dragon

Laut Jon Skeet in C # in Depth war die Verwendung einer verschachtelten Klasse die einzige Möglichkeit, einen vollständig faulen threadsicheren Singleton (siehe fünfte Version) (bis .NET 4) zu implementieren.

2
Scott Whitlock

Private und innere Klassen werden verwendet, um die Kapselungsstufe zu erhöhen und Implementierungsdetails auszublenden.

In C++ kann zusätzlich zu einer privaten Klasse dasselbe Konzept erreicht werden, indem der anonyme Namespace einer Klasse cpp implementiert wird. Dies dient dazu, ein Implementierungsdetail zu verbergen/zu privatisieren.

Es ist die gleiche Idee wie eine innere oder private Klasse, jedoch auf einer noch größeren Ebene der Kapselung, da sie außerhalb der Kompilierungseinheit der Datei vollständig unsichtbar ist. Nichts davon erscheint in der Header-Datei oder ist in der Deklaration der Klasse äußerlich sichtbar.

1
hiwaylon