Frage

Eine Sache, die ich in ein paar Mal laufen habe, ist eine Serviceklasse (wie ein JBoss-Dienst), die aufgrund der Helfer zu großen inneren Klassen bekommen hat. Ich habe noch einen guten Weg zu finden, um die Klasse zu brechen. Diese Helfer sind in der Regel Themen. Hier ein Beispiel:

/** Asset service keeps track of the metadata about assets that live on other
 * systems. Complications include the fact the assets have a lifecycle and their
 * physical representation lives on other systems that have to be polled to find
 * out if the Asset is still there. */
public class AssetService
{
  //...various private variables
  //...various methods

  public AssetService()
  {
    Job pollerJob = jobService.schedule( new AssetPoller() );
    Job lifeCycleJob = jobService.schedule( AssetLifecycleMonitor() );
  }

  class AssetPoller
  {
    public void run()
    { 
      // contact remote systems and update this service's private variables that
      // track the assets.
    }
  }

  class AssetLifecycleMonitor
  {
    public void run()
    {
      // look for assets that have meet criteria for a lifecycle shift
      // and update this service's private variables as relevant.
    }
  }
}

Also, was passieren kann, wenn ich ein paar Helfer haben und sie bei allen komplexen sind, dann ist die gesamte Klassendatei wirklich groß werden kann. Ich mag die inneren Klassen, dass sie die Klassen deutlich machen, sind vollständig durch den Dienst im Besitz und existieren nur diesen Dienst zu helfen. Ich habe versucht, aus den Klassen zu brechen und das Bestehen der Mutter Dienst als Referenz, die meistens funktioniert, aber die Dinge Ich mag es nicht sind:  

  • ich am Ende Paketebene Accessoren aussetzt, so dass die Klassen ausgebrochen auf die Variablen bekommen, während, bevor ich überhaupt die Setter nicht aussetzen habe, da die inneren Klassen direkten Zugang hatten.  
  • Plus, werden die Dinge ein bisschen mehr wortreich wie ich ständig bin Accessoren, anstatt die zugrunde liegenden Variablen aufrufen. Eine kleinere nit, gewährt.  
  • Convenience-Methoden (z checkAssetIsValid () oder so) müssen Paketebene Belichtung jetzt so die Helferklassen aufrufen können sie, wo nach wie vor als innere Klassen, die sie privat sein könnte.  
  • Schlimmer noch, ich brauche die Service-Implementierungsklasse zu der Hilfsklassen Konstrukteurs passieren, da will ich nicht diese Helfer Methoden in der Schnittstelle belichten des Dienst implementiert, weil das sie öffentlich sein zwingt. Dies kann einige Unit-Test / spöttischen Fragen erstellen.  
  • Schlimmer noch, jede Synchronisation ich durch einige externe bequeme Methode durchgesickert tun wollte, wird (zum Beispiel lockDownAssets () während eines poller-Update). Bevor die internen Klassen Zugang zu privaten Locks hatte.

    Also, kurz gesagt, verliert die Klassen heraus brechen einige der Verkapselung Ich mag. Aber sie verlassen kann zu einigen großen Java-Dateien führen. Ich habe noch einen guten Weg zu finden, um damit umzugehen. C ++ hatte das Konzept der „Freunde“, die ich selten verpasst haben, würde aber in diesem Fall tatsächlich helfen.

    Die Gedanken?

        
  • War es hilfreich?

    Lösung

    Auf Bytecode Ebene innere Klassen sind einfach nur Java-Klassen. Da der Java-Bytecode Verifier Zugang zu nicht privaten Mitgliedern erlaubt, erzeugen sie synthetische Accessormethoden für jeden privaten Bereich, die Sie verwenden. Auch, um die innere Klasse mit seiner umschließenden Instanz zu verknüpfen, der Compiler fügt synthetische Zeiger auf den äußeren ‚this‘.

    Diese Erwägung, sind die inneren Klassen nur eine Schicht von Syntax Zucker. Sie sind bequem, und Sie haben einige gute Punkte aufgelistet, also würde ich einige negative Aspekte aufzuzählen, die Sie vielleicht prüfen:

    • Ihre innere Klasse hat eine versteckte Abhängigkeit zu der ganzer Elternklasse, die ihr Inbound-Interface verschleiert. Wenn Sie es als Paket-private Klasse extrahieren haben Sie eine Chance, Ihr Design zu verbessern und besser verwaltbar zu machen. Am Anfang ist es ausführlicher, aber oft würden Sie feststellen, dass:
      • Anstelle von 10 Accessoren aussetzt eigentlich Sie wollen einen einzelnen Wert Objekt teilen. Oft würden Sie feststellen, dass Sie wirklich nicht, einen Verweis auf die gesamte äußere Klasse benötigen. Dies funktioniert auch gut mit IoC.
      • Statt Methoden für explizite Verriegelungs Bereitstellung, es ist besser verwaltbar die Operation mit seinem Kontext in einer separaten Klasse zu kapseln (oder zu einem der beiden Klassen bewegen - Außen- oder Innen früher-).
      • Convenience Methoden gehören im Paket privaten Utility-Klassen. Sie können die Java5 statischen Import verwenden, um sie als lokal erscheinen.
    • Ihre äußeree Klasse umgehen kann alle Schutzstufen und den Zugang private Mitglieder Ihrer inneren Klasse direkt. Das ist nicht schlecht, was per se, aber es nimmt eine der Sprache mittels Ihr Design zum Ausdruck.
    • Da Ihre innere Klasse in genau einer äußeren Klasse eingebettet ist, ist der einzige Weg, um es wieder zu verwenden ist, um die äußere Klasse, Unterklasse. Eine Alternative wäre, explizit auf einen Paket-private Schnittstelle übergeben, die die äußere Klasse implementiert. Dies würde ermöglichen es Ihnen, die äußere und die besseren Test der inneren Klasse zu verspotten.
    • Obwohl kürzlich Debugger recht gut sind, ich habe Probleme erlebt mit dem Debuggen innere Klassen vor (bedingtem Haltepunkt Umfang Verwirrung, nicht an Haltepunkten zu stoppen, etc.)
    • Privatunterricht aufblasen Ihre Bytecode. Siehe meinen ersten Absatz -. Oft gibt es eine API, die Sie nutzen könnten und reduzieren die Anzahl der synthetischen cruft

    P. S. Ich spreche über nicht-triviale innere Klassen (vor allem diejenigen, die keine Schnittstellen nicht implementiert). Drei Linie Zuhörer Implementierungen sind gut.

    Andere Tipps

    Vergessen Sie nicht darüber nachdenken, warum Sie versuchen, Ihre große Klasse zu brechen. Ist es für Software-Engineering-Zwecke? Z.B. es ist eine Hotspot-Programmierung, und Sie haben eine so große Datei es kompliziert verschmilzt auf dem Entwickler-Team verursacht?

    Ist es nur ein allgemeiner Wunsch große Klassen zu vermeiden? In diesem Fall kann es sein, dass Sie Ihre Zeit besser den Code ausgegeben würde verbessern Sie tun.

    Ist der Code immer schwieriger zu verwalten, z Debugging und die Gewährleistung Vermeidung von unbeabsichtigten Nebenwirkungen wird immer schwieriger.

    Rick Kommentar über Unit-Tests unter Verwendung von fort konsistentes Verhalten sicherzustellen, ist sehr wertvoll und eine gute Idee. Es kann sein, dass der aktuelle Entwurf einfach Refactoring ausschließt und du bist besser dran Neuimplementierung das gleiche Verhalten von der Schnittstelle des ursprünglichen Ausgangs. Seien Sie bereit für viel regresssion Testen!

    Die Grenze zwischen Verkapselung und Trennung kann schwer zu gehen sein. Aber ich denke, die hier Hauptproblem ist, dass Sie irgendeine Art von festem Wechselwirkungsmodell benötigen als Grundlage zu verwenden, um Ihre Klassen zu trennen.

    Ich denke, es ist vernünftig externe Helfer Utility-Klassen zu haben, die an vielen Orten verwendet werden, solange sie Wirkung nicht Seite kann ich tun, nicht um ein Problem sehen. Es ist auch sinnvoll statische Hilfsklassen zu haben, solange sie gut organisiert sind, die enthalten oft verwendete Methoden wie checkAssetIsValid (). Das setzt voraus, dass checkAssetIsValid keinen externen anderen Zustand zugreifen muß als das Objekt, das Sie es sind vorbei.

    Das Wichtigste für die Trennung ist nicht Objekte zu haben, die diese Klassen in vielen permanenten Referenzen teilen. Ich mag in der funktionalen Programmierung zur Orientierung suchen. Jede Klasse sollte nicht in die Eingeweide anderer Klassen erreicht und den Zustand ändert. Statt jede Klasse, die funktionierts sollte produzieren und Containerobjekte verbrauchen.

    Visualisierung kann auch sehr hilfreich sein. Ich bemerkte einen Thread zum Thema Java Visualisierungstool hier . Idealerweise sollte Ihre Klasse Interaktionsdiagramm mehr aussehen wie ein Baum als ein Diagramm.

    Auch ich möchte nur beachten Sie, dass in kleineren Klassen eine große Klasse Refactoring kann extrem schwierig sein. Es ist am besten, eine Suite von Unit-Tests für die öffentliche Schnittstelle zumindest zu bauen, so dass es sofort offensichtlich werden, wenn Sie etwas brechen. Ich weiß, dass Tests gespeichert haben mir unzählige Stunden in der Vergangenheit.

    Hoffentlich einige dieser wird hilfreich sein. Ich bin ein bisschen nur Wandern auf hier.

    Ich bin kein Fan von übermäßigem Einsatz von inneren Klassen. Ich denke, dass sie nicht wirklich keinen Vorteil bieten (wenn im Extreme verwendet wird), dass der Code in einer normalen Klasse setzen würde nicht, und sie dienen nur die Klassendatei unnötig groß und schwer zu machen zu folgen.

    Was ist der Schaden, wenn Sie die Sichtbarkeit von einigen Methoden zu erhöhen haben? Wird es vollständig Ihre Abstraktion oder eine Schnittstelle brechen? Ich denke zu oft Programmierer neigen dazu, alles standardmäßig privat zu machen, wo es in der Vermietung einige andere Klassen rufen Sie Ihre Methoden nicht wirklich viel von einem Schaden ist -. Wenn Ihr Design wirklich OO-basiert ist, das heißt

    Wenn alle Ihre „innere Hilfsklassen“ Zugang zu einigen der gleichen Methoden benötigen, sollten sie in einer Basisklasse setzen, so dass sie über Vererbung geteilt werden.

    Yeap. Wahrscheinlich müssen Sie diese Helfer erneut umgestalten und sich nicht bewegen sie alle wie sie sind. Einige Dinge gehören zum Service einige andere Helfer. Eventuelle neue Klassen sollten die Daten kapseln verwendet werden.

    Ein posibility Sie verwenden können, ist zu AOP bietet eine präziseren Zugriff und umfasst in dem Punkt schneiden, dass das Verfahren nur aus der „Freund“ Klasse aufgerufen werden. Noch Ihre Methode ausgesetzt sein würde :(

    Ich denke, es gibt keine einfache Lösung.

    Lizenziert unter: CC-BY-SA mit Zuschreibung
    Nicht verbunden mit StackOverflow
    scroll top