Wie kapseln Sie interne Klassen in eine in Java geschriebene API?


9

Wir müssen eine Bibliothek schreiben. Natürlich sollte es nur eine sehr kleine API haben (so breit wie nötig, so klein wie möglich). Die Interna der Bibliothek sind etwas komplex. Daher müssen sie strukturiert werden.

Für die Strukturierung sehe ich derzeit zwei Möglichkeiten:

1. Verwenden Sie Pakete.

Profis: Die Bibliothek kann ordentlich strukturiert werden. Alles an seinem Platz.

Nachteile: Die Verwendung von Klassen über Paketgrenzen hinweg erfordert öffentliche Klassen und erweitert daher die API der gesamten Bibliothek.

2. Verwenden Sie statische innere Klassen in einem Paket.

Profis: Es werden nur sehr wenig öffentliche Dinge (Klassen, Methoden usw.) benötigt.

Nachteile: Klassen werden nur ausgeblendet, um sie zu strukturieren. Dies wäre einer der wenigen Anwendungsfälle, in denen so viele statische innere Klassen verwendet werden. Entwickler sind daran nicht gewöhnt und übersehen sie möglicherweise.


Gibt es einen besseren Weg, um eine kleine API in einer gut strukturierten Bibliothek zu erreichen?

Bearbeiten: Ich habe vergessen zu erwähnen: Es ist für eine Android-Bibliothek. Daher kein Java9.


Warum müssen deine inneren Klassen statisch sein?
David Arno

Machen innere Klassen Codeeinheiten nicht größer? Ich meine, eine Klasse mit mehreren inneren Klassen kann sehr lang werden.
Tulains Córdova

2
@ TulainsCórdova, guter Punkt, ich habe den Begriff "inner" als "intern" gelesen, was Java meiner Meinung nach "package-private" nennt. Der normale Weg, eine Bibliothek zu erstellen, besteht sicherlich darin, ein Paket zu haben, das einige öffentliche Klassen enthält, wobei alles andere intern / paketprivat ist.
David Arno

Hallo @frmarkus. Ich habe versucht, Ihren Fragentitel neu zu schreiben, um genauer zu sein und zu vermeiden, dass "unklar ist, was Sie fragen". Sie können es jederzeit erneut bearbeiten, wenn Sie der Meinung sind, dass es Ihre eigentliche Frage falsch darstellt.
Andres F.

1
@ TulainsCórdova: Ja, die Codeeinheiten werden viel zu groß (3.000 Codezeilen pro Datei). Das ist ein weiteres wichtiges Problem dieser Art der Strukturierung.
Markus Frauenfelder

Antworten:


1

Ich sehe, was Sie mit 2 machen. Sie verwenden Klassen als Pakete und Pakete als Module, damit Sie sich innerhalb des Pakets isolieren und dennoch innerhalb des Pakets mithilfe von Klassen organisieren können.

Das ist sehr klug. Vorsicht vor klug.

Dadurch werden Sie gezwungen, mehrere Klassen in derselben Quelldatei zu blockieren (was Sie vielleicht bevorzugen), und der Pfad enthält ein Wort mit Großbuchstaben.

Dies zwingt Sie auch dazu, Testcode innerhalb des Pakets zu schreiben, es sei denn, Sie verwenden Reflection, um sich von außen hineinzuhacken.

Andernfalls wird dies funktionieren. Es wird einfach komisch erscheinen.

Menschen sind eher daran gewöhnt , dass innere Klassen wie EntrySet in Hashtable verwendet werden. Es ist privat, daher kann ich es nicht erstellen, aber es implementiert eine öffentliche Schnittstelle, sodass ich einfach über die Schnittstelle mit ihr spreche und mir etwas besorgen kann.

Aber Sie beschreiben Klassen, mit denen ich nicht einmal über eine Schnittstelle sprechen soll. Also keine Schnittstelle für mich. Dies bedeutet, dass ich nichts zu sehen habe und verwirrt bin (es sei denn, Sie geben mir die Quelle).

Das größte Problem, das ich sehe, sind verwirrende Neulinge, die die API warten. Sie können Dokumentationen und Kommentare auf sie werfen, aber seien Sie nicht übergroß, wenn sie keine lesen oder ihnen vertrauen.

Sie haben ein weiteres Muster erstellt, das einen Sprachmangel ausgleicht. Java hat keinen Zugriffsmodifikator, der den Zugriff auf eine Gruppe von Paketen gewährt. Ich habe gehört, dass ein "Modul" -Zugriffsmodifikator vorgeschlagen wurde, sehe aber keine Anzeichen dafür.

Der Standardzugriffsmodifikator (kein Modifikator) wird wahrscheinlich hier verwendet, es sei denn, es macht Ihnen nichts aus, dass ich mich durch die Vererbung einschleiche. In diesem Fall ist er geschützt.

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N 

Was Sie wirklich wollen, ist Modulzugriff. Auf diese Weise können Sie Ihre Tests in einem Paket und den Code in einem anderen aufbewahren. Leider haben wir es nicht in Java.

Die meisten Leute machen nur 1 und erweitern die API. Die ordnungsgemäße Verwendung von Schnittstellen entlastet die Implementierung.

Das Hacken, was Sie wollen, in 1 ist noch hässlicher. Schauen Sie sich den Aufrufstapel an und lösen Sie eine Ausnahme aus, wenn das, was Sie angerufen haben, aus einem Paket stammt, das Sie nicht mögen. Eeew.


2

Trennen Sie Ihren Code auf jeden Fall in Pakete. Dies wird einen großen Beitrag zur Verbesserung der Wartbarkeit leisten.

Um zu verhindern, dass Endbenutzer auf Dinge zugreifen, die sie nicht sollten, müssen Sie Ihre API in Schnittstelle und Implementierung unterteilen.

Sie können dies im wahrsten Sinne des Wortes tun, indem Sie die gesamte API in Form von Java-Schnittstellen definieren und eine Reihe von Factory-Klassen bereitstellen, um Implementierungsobjekte zu erstellen. Dies ist, was JDBC tut.

Sie können dies auch über Konventionen tun, indem Sie internalPakete erstellen und diese Pakete als implementierungsabhängig dokumentieren und ohne Vorwarnung oder Abwärtskompatibilität ändern.


1
Leider ist dies ein absolutes No Go. Dies überlässt vielen öffentlichen Klassen. Sie könnten Hinweise haben (Fabriken oder "intern"). Aber ich muss zusätzliche Werkzeuge auf sie anwenden (auf alle öffentlichen Klassen), das ist einfach nicht gut.
Markus Frauenfelder

@frmarkus - Ich denke, dass (1) Sie viel zu viel von Zugriffskontrollen erwarten oder (2) Sie Ihre Paketstruktur überdenken müssen, damit Klassen aus einem Paket nicht von Klassen aus einem anderen abhängen müssen Paket (wenn Sie alles als statisch verschachtelte Klassen behalten können, sollte dies nicht schwierig sein).
kdgregory
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.