Comment encapsuler des classes internes dans une API écrite en Java?


9

Nous devons écrire une bibliothèque. Naturellement, il ne devrait avoir qu'une très petite API (aussi large que nécessaire et aussi petite que possible). Les éléments internes de la bibliothèque sont quelque peu complexes. Par conséquent, ils doivent être structurés.

Pour la structuration, je vois actuellement deux façons:

1. utilisez des packages.

avantages: la bibliothèque peut être bien structurée. Tout à sa place.

inconvénients: l' utilisation des classes à travers les frontières des packages a besoin de classes publiques et donc d'élargir l'API de toute la bibliothèque.

2. utilisez des classes internes statiques, le tout dans un seul paquet.

pour: très peu de choses publiques (classes, méthodes, etc.) nécessaires.

inconvénients: les classes sont masquées uniquement pour les structurer. Ce serait l'un des très rares cas d'utilisation où tant de classes internes statiques sont utilisées. Les développeurs ne sont pas habitués à cela et peuvent les ignorer.


Existe-t-il un meilleur moyen de réaliser une petite API dans une bibliothèque bien structurée?

Edit: j'ai oublié de mentionner: c'est pour une bibliothèque Android. Par conséquent, pas de java9.


Pourquoi vos classes internes doivent-elles être statiques?
David Arno

Les classes internes n'agrandissent-elles pas les unités de code? Je veux dire qu'une classe avec plusieurs classes internes peut devenir très longue.
Tulains Córdova

2
@ TulainsCórdova, bon point, j'ai lu le terme "interne" comme "interne", que je pense que Java appelle "package-privé". La façon normale de créer une bibliothèque est sûrement d'avoir un paquet, contenant quelques classes publiques, tout le reste étant interne / paquet-privé.
David Arno

Salut @frmarkus. J'ai essayé de réécrire le titre de votre question pour être plus précis et éviter les votes serrés "pas clair ce que vous demandez". N'hésitez pas à le rééditer si vous pensez qu'il déforme votre question réelle.
Andres F.

1
@ TulainsCórdova: Oui, les unités de code deviennent trop grandes (3k lignes de code par fichier). C'est un autre problème important de cette façon de structurer.
Markus Frauenfelder

Réponses:


1

Je vois ce que vous faites avec 2. Vous utilisez des classes en tant que packages et des packages en tant que modules afin que vous puissiez vous isoler dans le package mais toujours organiser au sein du package à l'aide de classes.

C'est très intelligent. Méfiez-vous des intelligents.

Cela vous obligera à bloquer plusieurs classes dans le même fichier source (que vous préférerez peut-être) et le chemin aura un mot en majuscule supplémentaire.

Cela vous obligera également à écrire tout code de test dans le package, sauf si vous utilisez la réflexion pour pirater votre chemin depuis l'extérieur.

Autre que cela, cela fonctionnera. Cela semblera juste bizarre.

Les gens sont plus habitués aux classes internes utilisées comme EntrySet dans Hashtable. Il est privé, donc je ne peux pas le créer, mais il implémente une interface publique, je lui parle donc via l'interface et j'en ai une pour moi.

Mais vous décrivez des classes auxquelles vous ne voulez pas que je parle, même via une interface. Donc pas d'interface pour moi. Cela signifie que je n'ai rien à regarder et que je ne suis pas confus (sauf si vous me fournissez la source).

Le plus gros problème que je prévois est le débutant déroutant de la maintenance de l'API. Vous pouvez leur envoyer de la documentation et des commentaires, mais ne soyez pas surdimensionné lorsqu'ils ne lisent ni ne font confiance à aucun d'eux.

Vous avez créé un autre modèle qui compense une déficience de la langue. Java n'a aucun modificateur d'accès qui accorde l'accès à un groupe de packages. J'ai entendu dire qu'un modificateur d'accès "module" avait été proposé mais je ne vois aucun signe que cela se produise.

Le modificateur d'accès par défaut (pas de modificateur) est probablement ce que vous utiliserez ici, sauf si cela ne vous dérange pas de me faufiler par héritage, auquel cas protégé.

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 

Ce que vous voulez vraiment, c'est l'accès au module. De cette façon, vous pouvez conserver vos tests dans un package et le code dans un autre. Malheureusement, nous ne l'avons pas en Java.

La plupart des gens font juste 1 et développent l'API. Une bonne utilisation des interfaces évite la mise en œuvre.

Pirater ce que vous voulez en 1 est encore plus laid. Jetez un œil à la pile d'appels et lancez une exception chaque fois que ce qui vous a appelé provient d'un package que vous n'aimez pas. Eeew.


3

Par tous les moyens, séparez votre code en packages. Cela contribuera grandement à améliorer la maintenabilité.

Pour empêcher les utilisateurs finaux d'accéder à des choses qu'ils ne devraient pas, vous devez séparer votre API en interface et en implémentation.

Vous pouvez le faire très littéralement, en définissant l'ensemble de l'API en termes d'interfaces Java et en fournissant un certain nombre de classes d'usine pour produire des objets d'implémentation. C'est ce que fait JDBC.

Ou vous pouvez le faire via la convention, en créant des internalpackages et en documentant ces packages comme dépendants de l'implémentation et sujets à changement sans avertissement ni compatibilité descendante.


1
Malheureusement, c'est un non complet. Cela laisse à de nombreuses classes publiques. Ils peuvent avoir des indices (étant des usines ou «internes»). Mais je dois leur appliquer des outils supplémentaires (à toutes les classes publiques), ce n'est tout simplement pas bon.
Markus Frauenfelder

@frmarkus - Je pense que (1) vous attendez beaucoup trop des contrôles d'accès, ou (2) vous devez repenser la structure de votre package afin que les classes d'un package n'aient pas besoin de dépendre des classes d'un autre package (si vous pouvez tout garder en tant que classes imbriquées statiques, cela ne devrait pas être difficile).
kdgregory
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.