Ich habe vor einiger Zeit darüber nachgedacht und es ist kürzlich wieder aufgetaucht, als mein Shop seine erste echte Java-Web-App macht.
Als Intro sehe ich zwei Hauptstrategien zur Benennung von Paketen. (Um klar zu sein, ich beziehe mich nicht auf den gesamten Teil von 'domain.company.project', ich spreche über die Paketkonvention darunter.) Wie auch immer, die Paketbenennungskonventionen, die ich sehe, lauten wie folgt:
Funktional: Benennen Sie Ihre Pakete architektonisch nach ihrer Funktion und nicht nach ihrer Identität gemäß der Geschäftsdomäne. Ein anderer Begriff hierfür könnte die Benennung nach "Schicht" sein. Sie hätten also ein * .ui-Paket und ein * .domain-Paket und ein * .orm-Paket. Ihre Pakete sind eher horizontale als vertikale Scheiben.
Dies ist weitaus häufiger als die logische Benennung. Tatsächlich glaube ich nicht, dass ich jemals ein Projekt gesehen oder gehört habe, das dies tut. Das macht mich natürlich misstrauisch (so als würde ich denken, dass Sie eine Lösung für ein NP-Problem gefunden haben), da ich nicht besonders schlau bin und davon ausgehe, dass jeder gute Gründe haben muss, es so zu machen, wie er es tut. Auf der anderen Seite bin ich nicht gegen Leute, die nur den Elefanten im Raum vermissen, und ich habe noch nie ein Argument dafür gehört , wie man Pakete so benennt. Es scheint nur der De-facto-Standard zu sein.
Logisch: Benennen Sie Ihre Pakete nach ihrer Geschäftsdomänenidentität und fügen Sie jede Klasse, die mit diesem vertikalen Funktionsbereich zu tun hat, in dieses Paket ein.
Ich habe das noch nie gesehen oder gehört, wie ich bereits erwähnt habe, aber es macht für mich eine Menge Sinn.
Ich nähere mich eher vertikalen als horizontalen Systemen. Ich möchte das Auftragsabwicklungssystem entwickeln, nicht die Datenzugriffsschicht. Natürlich besteht eine gute Chance, dass ich bei der Entwicklung dieses Systems die Datenzugriffsschicht berühre, aber der Punkt ist, dass ich das nicht so sehe. Dies bedeutet natürlich, dass es schön wäre, wenn ich einen Änderungsauftrag erhalte oder eine neue Funktion implementieren möchte, nicht in einer Reihe von Paketen herumfischen zu müssen, um alle zugehörigen Klassen zu finden. Stattdessen schaue ich einfach in das X-Paket, weil das, was ich tue, mit X zu tun hat.
Unter Entwicklungsgesichtspunkten sehe ich es als großen Vorteil an, dass Ihre Pakete eher Ihre Geschäftsdomäne als Ihre Architektur dokumentieren. Ich bin der Meinung, dass die Domäne fast immer der Teil des Systems ist, der schwieriger zu erfassen ist, da die Architektur des Systems, insbesondere zu diesem Zeitpunkt, in seiner Implementierung fast banal wird. Die Tatsache, dass ich mit dieser Art von Namenskonvention zu einem System kommen kann und sofort aus der Benennung der Pakete weiß, dass es sich um Bestellungen, Kunden, Unternehmen, Produkte usw. handelt, scheint verdammt praktisch.
Dies scheint es Ihnen zu ermöglichen, die Zugriffsmodifikatoren von Java besser zu nutzen. Auf diese Weise können Sie Schnittstellen in Subsystemen viel sauberer definieren als in Schichten des Systems. Wenn Sie also ein Auftragssubsystem haben, das transparent persistent sein soll, können Sie theoretisch nie etwas anderes wissen lassen, dass es persistent ist, indem Sie keine öffentlichen Schnittstellen zu seinen Persistenzklassen in der Dao-Schicht erstellen und stattdessen die Dao-Klasse in packen müssen mit nur den Klassen, mit denen es sich befasst. Wenn Sie diese Funktionalität verfügbar machen möchten, können Sie natürlich eine Schnittstelle dafür bereitstellen oder sie öffentlich machen. Es scheint nur so, als ob Sie viel davon verlieren, wenn Sie einen vertikalen Teil der Funktionen Ihres Systems auf mehrere Pakete verteilen.
Ich nehme an, ein Nachteil, den ich sehen kann, ist, dass es das Herausreißen von Schichten etwas schwieriger macht. Anstatt nur ein Paket zu löschen oder umzubenennen und dann ein neues mit einer alternativen Technologie zu entfernen, müssen Sie alle Klassen in allen Paketen ändern. Ich sehe jedoch nicht, dass dies eine große Sache ist. Es mag an mangelnder Erfahrung liegen, aber ich muss mir vorstellen, dass die Häufigkeit, mit der Sie Technologien austauschen, im Vergleich zu der Häufigkeit, mit der Sie vertikale Feature-Slices in Ihrem System bearbeiten, verblasst.
Ich denke also, die Frage würde dann an Sie gehen, wie benennen Sie Ihre Pakete und warum? Bitte haben Sie Verständnis dafür, dass ich nicht unbedingt denke, dass ich hier auf die goldene Gans oder so gestoßen bin. Ich bin ziemlich neu in all dem mit größtenteils akademischer Erfahrung. Ich kann jedoch die Löcher in meiner Argumentation nicht erkennen, also hoffe ich, dass Sie alle es können, damit ich weitermachen kann.
quelle
Antworten:
Beim Verpackungsdesign teile ich zuerst nach Ebenen und dann nach anderen Funktionen.
Es gibt einige zusätzliche Regeln:
So könnten Sie beispielsweise für eine Webanwendung die folgenden Ebenen in Ihrer Anwendungsebene haben (von oben nach unten):
Für das resultierende Paketlayout gelten folgende zusätzliche Regeln:
<prefix.company>.<appname>.<layer>
<root>.<logic>
<root>.private
Hier ist ein Beispiellayout.
Die Präsentationsebene ist nach Ansichtstechnologie und optional nach (Gruppen von) Anwendungen unterteilt.
Die Anwendungsschicht ist in Anwendungsfälle unterteilt.
Die Service-Schicht ist in Geschäftsdomänen unterteilt, die von der Domänenlogik in einer Backend-Schicht beeinflusst werden.
Die Integrationsschicht ist in "Technologien" und Zugriffsobjekte unterteilt.
Der Vorteil der Trennung solcher Pakete besteht darin, dass die Komplexität einfacher verwaltet werden kann und die Testbarkeit und Wiederverwendbarkeit erhöht wird. Obwohl es nach viel Aufwand aussieht, ist es meiner Erfahrung nach sehr natürlich und jeder, der an dieser Struktur (oder ähnlichem) arbeitet, nimmt es in wenigen Tagen auf.
Warum finde ich den vertikalen Ansatz nicht so gut?
In dem Schichtmodell können mehrere verschiedene übergeordnete Module dasselbe untergeordnete Modul verwenden. Beispiel: Sie können mehrere Ansichten für dieselbe Anwendung erstellen, mehrere Anwendungen können denselben Dienst verwenden, mehrere Dienste können dasselbe Gateway verwenden. Der Trick dabei ist, dass sich beim Durchlaufen der Ebenen die Funktionalität ändert. Module in spezifischeren Ebenen werden auf Modulen der allgemeineren Ebene nicht 1-1 zugeordnet, da die von ihnen ausgedrückten Funktionalitätsebenen nicht 1-1 zugeordnet werden.
Wenn Sie den vertikalen Ansatz für Package - Design verwenden, dh Sie können durch Funktionalität teilen zuerst, dann zwingen Sie alle Bausteine mit unterschiedlichen Ebenen der Funktionalität in die gleiche ‚-Funktionalität Jacke‘. Sie können Ihre allgemeinen Module für das spezifischere entwerfen. Dies verstößt jedoch gegen das wichtige Prinzip, dass die allgemeinere Schicht keine spezifischeren Schichten kennen sollte. Die Service-Schicht sollte beispielsweise nicht nach Konzepten aus der Anwendungsschicht modelliert werden.
quelle
Ich halte mich an die Verpackungsprinzipien von Onkel Bob . Kurz gesagt, Klassen, die zusammen wiederverwendet und gemeinsam geändert werden sollen (aus demselben Grund, z. B. eine Abhängigkeitsänderung oder eine Framework-Änderung), sollten in dasselbe Paket aufgenommen werden. IMO, die Funktionsaufteilung hätte bessere Chancen, diese Ziele zu erreichen als die vertikale / geschäftsspezifische Aufteilung in den meisten Anwendungen.
Beispielsweise kann ein horizontaler Teil von Domänenobjekten von verschiedenen Arten von Frontends oder sogar Anwendungen wiederverwendet werden, und ein horizontaler Teil des Web-Frontends ändert sich wahrscheinlich zusammen, wenn das zugrunde liegende Webframework geändert werden muss. Andererseits ist es leicht vorstellbar, wie sich diese Änderungen auf viele Pakete auswirken, wenn Klassen in verschiedenen Funktionsbereichen in diesen Paketen gruppiert sind.
Offensichtlich sind nicht alle Arten von Software gleich, und die vertikale Aufteilung kann in bestimmten Projekten sinnvoll sein (im Hinblick auf das Erreichen der Ziele der Wiederverwendbarkeit und der Nähe zu Änderungen).
quelle
In der Regel sind beide Teilungsebenen vorhanden. Von oben gibt es Bereitstellungseinheiten. Diese werden als "logisch" bezeichnet (denken Sie in Ihren Begriffen an Eclipse-Funktionen). Innerhalb der Bereitstellungseinheit haben Sie eine funktionale Aufteilung der Pakete (denken Sie an Eclipse-Plugins).
Zum Beispiel Merkmal ist
com.feature
, und es besteht auscom.feature.client
,com.feature.core
undcom.feature.ui
Plugins. Innerhalb von Plugins habe ich sehr wenig Unterteilung in andere Pakete, obwohl das auch nicht ungewöhnlich ist.Update: Übrigens gibt es bei InfoQ ein großartiges Gespräch von Jürgen Hoeller über die Code-Organisation: http://www.infoq.com/presentations/code-organization-large-projects . Jürgen ist einer der Architekten des Frühlings und weiß viel über dieses Zeug.
quelle
Die meisten Java-Projekte, an denen ich gearbeitet habe, schneiden die Java-Pakete zuerst funktional und dann logisch auf.
Normalerweise sind Teile so groß, dass sie in separate Build-Artefakte aufgeteilt werden, in denen Sie Kernfunktionen in ein Glas, Apis in ein anderes, Web-Frontend-Inhalte in ein Warfile usw. integrieren können.
quelle
Pakete sind als Einheit zusammenzustellen und zu verteilen. Bei der Überlegung, welche Klassen zu einem Paket gehören, sind die Abhängigkeiten eines der Hauptkriterien. Von welchen anderen Paketen (einschließlich Bibliotheken von Drittanbietern) diese Klasse abhängt. Ein gut organisiertes System gruppiert Klassen mit ähnlichen Abhängigkeiten in einem Paket. Dies begrenzt die Auswirkungen einer Änderung in einer Bibliothek, da nur wenige genau definierte Pakete davon abhängen.
Es hört sich so an, als ob Ihr logisches vertikales System dazu neigt, Abhängigkeiten über die meisten Pakete hinweg zu "verschmieren". Das heißt, wenn jedes Feature als vertikales Slice gepackt ist, hängt jedes Paket von jeder Bibliothek eines Drittanbieters ab, die Sie verwenden. Jede Änderung an einer Bibliothek wirkt sich wahrscheinlich auf Ihr gesamtes System aus.
quelle
Ich persönlich bevorzuge es, Klassen logisch zu gruppieren und dann ein Unterpaket für jede funktionale Teilnahme einzuschließen.
Ziele der Verpackung
Bei Paketen geht es schließlich darum, Dinge zu gruppieren - die Idee, verwandte Klassen zu sein, lebt nahe beieinander. Wenn sie im selben Paket leben, können sie das Paket private nutzen, um die Sichtbarkeit einzuschränken. Das Problem besteht darin, dass Sie alle Ihre Ansichten und Beständigkeitsdaten in einem Paket zusammenfassen. Dies kann dazu führen, dass viele Klassen in einem einzigen Paket zusammengefasst werden. Als nächstes ist es sinnvoll, Ansicht, Persistenz, Unterpakete und Refactor-Klassen entsprechend zu erstellen. Leider unterstützt das geschützte und private Paketumfang das Konzept des aktuellen Pakets und Unterpakets nicht, da dies bei der Durchsetzung solcher Sichtbarkeitsregeln hilfreich wäre.
Ich sehe jetzt Wert in der Trennung über Funktionalität, weil welcher Wert da ist, um alle sichtbezogenen Dinge zu gruppieren. Die Dinge in dieser Benennungsstrategie werden mit einigen Klassen in der Ansicht getrennt, während andere hartnäckig sind und so weiter.
Ein Beispiel für meine logische Verpackungsstruktur
Zur Veranschaulichung können wir zwei Module benennen. Verwenden Sie das Namensmodul als Konzept, das Klassen unter einem bestimmten Zweig eines Paketbaums gruppiert.
apple.model apple.store banana.model banana.storeVorteile
Ein Client, der den Banana.store.BananaStore verwendet, ist nur der Funktionalität ausgesetzt, die wir zur Verfügung stellen möchten. Die Version im Ruhezustand ist ein Implementierungsdetail, das sie nicht kennen müssen und das sie auch nicht sehen sollten, wenn sie den Speichervorgängen Unordnung hinzufügen.
Weitere logische v Funktionsvorteile
Je weiter oben an der Wurzel, desto breiter wird der Umfang und die Dinge, die zu einem Paket gehören, zeigen immer mehr Abhängigkeiten von Dingen, die zu anderen Modulen gehören. Wenn man zum Beispiel das "Bananen" -Modul untersuchen würde, wären die meisten Abhängigkeiten auf dieses Modul beschränkt. Tatsächlich würden die meisten Helfer unter "Banane" außerhalb dieses Paketumfangs überhaupt nicht referenziert.
Warum Funktionalität?
Welchen Wert erreicht man, wenn man Dinge auf der Grundlage der Funktionalität zusammenfasst? In einem solchen Fall sind die meisten Klassen unabhängig voneinander, wobei die privaten Methoden oder Klassen des Pakets kaum oder gar nicht genutzt werden müssen. Das Umgestalten in ihre eigenen Unterpakete bringt wenig, trägt aber dazu bei, die Unordnung zu verringern.
Entwickler ändert das System
Wenn Entwickler beauftragt werden, Änderungen vorzunehmen, die etwas mehr als trivial sind, erscheint es albern, dass sie möglicherweise Änderungen haben, die Dateien aus allen Bereichen des Paketbaums enthalten. Mit dem logisch strukturierten Ansatz sind ihre Änderungen lokaler im selben Teil des Paketbaums, der gerade richtig erscheint.
quelle
Beide funktionale (architektonische) als auch logische (Merkmals-) Verpackungsansätze haben ihren Platz. Viele Beispielanwendungen (die in Lehrbüchern usw. enthalten sind) folgen dem funktionalen Ansatz, Präsentation, Geschäftsdienste, Datenzuordnung und andere Architekturebenen in separate Pakete zu packen. In Beispielanwendungen hat jedes Paket oft nur wenige oder nur eine Klasse.
Dieser anfängliche Ansatz ist in Ordnung, da ein erfundenes Beispiel häufig dazu dient: 1) die Architektur des präsentierten Frameworks konzeptionell abzubilden, 2) dies mit einem einzigen logischen Zweck zu tun (z. B. Hinzufügen / Entfernen / Aktualisieren / Löschen von Haustieren aus einer Klinik). . Das Problem ist, dass viele Leser dies als einen Standard betrachten, der keine Grenzen kennt.
Wenn eine "Geschäfts" -Anwendung erweitert wird, werden immer mehr Funktionen hinzugefügt funktionalen Ansatzes zu einer Belastung. Obwohl ich weiß, wo ich nach Typen suchen muss, die auf der Architekturschicht basieren (z. B. Webcontroller unter einem "Web" - oder "UI" -Paket usw.), muss für die Entwicklung einer einzelnen logischen Funktion zwischen vielen Paketen hin und her gesprungen werden. Das ist zumindest umständlich, aber es ist schlimmer als das.
Da logisch verwandte Typen nicht zusammen gepackt werden, wird die API übermäßig veröffentlicht. Die Interaktion zwischen logisch verwandten Typen muss "öffentlich" sein, damit Typen importiert und miteinander interagieren können (die Möglichkeit, die Sichtbarkeit auf Standardwerte / Pakete zu minimieren, geht verloren).
Wenn ich eine Framework-Bibliothek erstelle, folgen meine Pakete auf jeden Fall einem funktionalen / architektonischen Verpackungsansatz. Meine API-Konsumenten wissen möglicherweise sogar zu schätzen, dass ihre Importanweisungen ein intuitives Paket enthalten, das nach der Architektur benannt ist.
Umgekehrt werde ich beim Erstellen einer Geschäftsanwendung nach Funktionen packen. Ich habe kein Problem damit, Widget, WidgetService und WidgetController alle im selben " com.myorg.widget " -Paket zu platzieren und dann die Standardsichtbarkeit zu nutzen (und weniger Importanweisungen sowie Abhängigkeiten zwischen Paketen zu haben).
Es gibt jedoch Überkreuzungsfälle. Wenn mein WidgetService von vielen logischen Domänen (Funktionen) verwendet wird, kann ich ein Paket " com.myorg.common.service. " Erstellen . Es besteht auch eine gute Chance, dass ich Klassen mit der Absicht erstelle, funktionsübergreifend wiederverwendbar zu sein und Pakete wie " com.myorg.common.ui.helpers. " Und " com.myorg.common.util " zu erhalten. Möglicherweise verschiebe ich sogar alle diese späteren "allgemeinen" Klassen in ein separates Projekt und füge sie als myorg-commons.jar-Abhängigkeit in meine Geschäftsanwendung ein.
quelle
Kommt es auf die Granularität Ihrer logischen Prozesse an?
Wenn sie eigenständig sind, haben Sie häufig ein neues Projekt für sie in der Quellcodeverwaltung und kein neues Paket.
Das Projekt, an dem ich gerade arbeite, geht in Richtung logische Aufteilung. Es gibt ein Paket für den Jython-Aspekt, ein Paket für eine Regel-Engine, Pakete für foo, bar, binglewozzle usw. Ich möchte die XML-spezifischen Parser haben /schreiber für jedes Modul in diesem Paket, anstatt ein XML-Paket zu haben (was ich zuvor getan habe), obwohl es immer noch ein XML-Kernpaket geben wird, in dem gemeinsame Logik verwendet wird. Ein Grund dafür ist jedoch, dass es möglicherweise erweiterbar ist (Plugins) und daher jedes Plugin auch seinen XML-Code (oder Datenbankcode usw.) definieren muss, sodass eine Zentralisierung später zu Problemen führen kann.
Am Ende scheint es so zu sein, wie es für das jeweilige Projekt am sinnvollsten erscheint. Ich denke, es ist jedoch einfach, nach dem Vorbild des typischen Projektschichtdiagramms zu verpacken. Sie erhalten eine Mischung aus logischer und funktionaler Verpackung.
Was benötigt wird, sind markierte Namespaces. Ein XML-Parser für einige Jython-Funktionen kann sowohl mit Jython als auch mit XML gekennzeichnet werden, anstatt den einen oder anderen auswählen zu müssen.
Oder vielleicht wackle ich.
quelle
Ich versuche, Paketstrukturen so zu gestalten, dass es beim Zeichnen eines Abhängigkeitsgraphen einfach ist, einem konsistenten Muster mit möglichst wenigen Zirkelverweisen zu folgen und es zu verwenden.
Für mich ist dies in einem vertikalen Benennungssystem viel einfacher zu pflegen und zu visualisieren als in einem horizontalen. Wenn component1.display einen Verweis auf component2.dataaccess hat, werden mehr Warnglocken ausgelöst, als wenn display.component1 einen Verweis auf dataaccess hat. Komponente2.
Natürlich werden die von beiden gemeinsam genutzten Komponenten in einem eigenen Paket zusammengefasst.
quelle
Ich folge voll und ganz und schlage die logische ("by-feature") Organisation vor! Ein Paket sollte dem Konzept eines "Moduls" so genau wie möglich folgen. Die funktionale Organisation kann ein Modul über ein Projekt verteilen, was zu einer geringeren Kapselung führt und anfällig für Änderungen der Implementierungsdetails ist.
Nehmen wir zum Beispiel ein Eclipse-Plugin: Alle Ansichten oder Aktionen in einem Paket zusammenzufassen, wäre ein Chaos. Stattdessen sollte jede Komponente eines Features in das Paket des Features oder, falls es viele gibt, in Unterpakete (featureA.handlers, featureA.preferences usw.) verschoben werden.
Das Problem liegt natürlich im hierarchischen Paketsystem (das unter anderem Java hat), das den Umgang mit orthogonalen Belangen unmöglich oder zumindest sehr schwierig macht - obwohl sie überall auftreten!
quelle
Ich würde mich persönlich für eine funktionale Benennung entscheiden. Der kurze Grund: Es vermeidet Codeduplizierung oder Abhängigkeitsalptraum.
Lassen Sie mich etwas näher darauf eingehen. Was passiert, wenn Sie eine externe JAR-Datei mit einem eigenen Paketbaum verwenden? Sie importieren effektiv den (kompilierten) Code in Ihr Projekt und damit einen (funktional getrennten) Paketbaum. Wäre es sinnvoll, die beiden Namenskonventionen gleichzeitig zu verwenden? Nein, es sei denn, das war dir verborgen. Und es ist, wenn Ihr Projekt klein genug ist und eine einzelne Komponente hat. Wenn Sie jedoch mehrere logische Einheiten haben, möchten Sie das Modul zum Laden von Datendateien wahrscheinlich nicht erneut implementieren. Sie möchten es zwischen logischen Einheiten teilen, keine künstlichen Abhängigkeiten zwischen logisch nicht verwandten Einheiten haben und müssen nicht auswählen, in welche Einheit Sie dieses bestimmte gemeinsam genutzte Tool einfügen möchten.
Ich denke, aus diesem Grund wird die funktionale Benennung am häufigsten in Projekten verwendet, die eine bestimmte Größe erreichen oder erreichen sollen, und die logische Benennung wird in Klassennamenskonventionen verwendet, um die spezifische Rolle zu verfolgen, wenn eine der Klassen in einer Paket.
Ich werde versuchen, auf jeden Ihrer Punkte zur logischen Benennung genauer zu antworten.
Wenn Sie in alten Klassen angeln müssen, um Funktionen zu ändern, wenn Sie Pläne ändern, ist dies ein Zeichen für eine schlechte Abstraktion: Sie sollten Klassen erstellen, die eine genau definierte Funktionalität bieten, die in einem kurzen Satz definiert werden kann. Nur wenige erstklassige Klassen sollten all diese zusammenstellen, um Ihre Business Intelligence widerzuspiegeln. Auf diese Weise können Sie mehr Code wiederverwenden, haben eine einfachere Wartung, eine klarere Dokumentation und weniger Abhängigkeitsprobleme.
Das hängt hauptsächlich davon ab, wie Sie Ihr Projekt bearbeiten. Auf jeden Fall sind die logische und die funktionale Ansicht orthogonal. Wenn Sie also eine Namenskonvention verwenden, müssen Sie die andere auf Klassennamen anwenden, um eine bestimmte Reihenfolge beizubehalten, oder von einer Namenskonvention zu einer anderen in einer bestimmten Tiefe wechseln.
Zugriffsmodifikatoren sind eine gute Möglichkeit, anderen Klassen, die Ihre Verarbeitung verstehen , den Zugriff auf die Innereien Ihrer Klasse zu ermöglichen. Logische Beziehung bedeutet nicht das Verständnis von algorithmischen oder Parallelitätsbeschränkungen. Funktionell kann, obwohl es nicht. Ich bin es sehr leid, andere Zugriffsmodifikatoren als öffentliche und private zu verwenden, da sie häufig einen Mangel an angemessener Architektur und Klassenabstraktion verbergen.
In großen kommerziellen Projekten kommt es häufiger zu einem Technologiewechsel, als Sie glauben. Zum Beispiel musste ich den XML-Parser bereits dreimal, die Caching-Technologie zweimal und die Geolokalisierungssoftware zweimal ändern. Gut, dass ich alle Details in einem speziellen Paket versteckt hatte ...
quelle
utils
Paket zu haben. Dann können alle Klassen, die es benötigen, einfach von diesem Paket abhängen.Es ist ein interessantes Experiment, überhaupt keine Pakete zu verwenden (mit Ausnahme des Root-Pakets).
Die Frage, die sich dann stellt, ist, wann und warum es sinnvoll ist, Pakete einzuführen. Vermutlich unterscheidet sich die Antwort von der, die Sie zu Beginn des Projekts beantwortet hätten.
Ich gehe davon aus, dass Ihre Frage überhaupt auftaucht, weil Pakete wie Kategorien sind und es manchmal schwierig ist, sich für das eine oder andere zu entscheiden. Manchmal wäre es besser, wenn Tags mitteilen würden, dass eine Klasse in vielen Kontexten verwendet werden kann.
quelle
Aus rein praktischer Sicht ermöglichen die Sichtbarkeitskonstrukte von Java Klassen im selben Paket den Zugriff auf Methoden und Eigenschaften mit
protected
unddefault
Sichtbarkeit sowie aufpublic
diejenigen. Die Verwendung nicht öffentlicher Methoden aus einer völlig anderen Codeebene wäre definitiv ein großer Codegeruch. Daher neige ich dazu, Klassen aus derselben Ebene in dasselbe Paket zu packen.Ich verwende diese geschützten oder Standardmethoden nicht oft an anderer Stelle - außer möglicherweise in den Komponententests für die Klasse -, aber wenn ich dies tue, stammt sie immer aus einer Klasse auf derselben Ebene
quelle
Es hängt davon ab, ob. In meiner Arbeit teilen wir Pakete manchmal nach Funktionen (Datenzugriff, Analyse) oder nach Anlageklassen (Kredit, Aktien, Zinssätze) auf. Wählen Sie einfach die Struktur aus, die für Ihr Team am bequemsten ist.
quelle
Nach meiner Erfahrung verursacht die Wiederverwendbarkeit mehr Probleme als das Lösen. Mit den neuesten und billigsten Prozessoren und Speicher würde ich es vorziehen, Code zu duplizieren, anstatt ihn eng zu integrieren, um ihn wiederzuverwenden.
quelle