web-dev-qa-db-fra.com

Comment minimiser A Java Surface d'interface exposée de la bibliothèque tout en décomposant la bibliothèque en sous-évaluations?

Je fais une bibliothèque ou deux pour et Android application et je souhaite garder les interfaces exposées de la bibliothèque au minimum pour éviter l'abstraction qui fuit partout en évitant de faire de toutes les classes "Public". Je suis également suivant structure de paquet de Maven .

En venant de C #, j'ai utilisé le modificateur d'accès internal pour accomplir ce que je veux; Si vous n'êtes pas familier, internal donne accès à quoi que ce soit dans l'assemblée, mais pas en dehors de celui-ci. Donc, les quelques interfaces publiques sont vraiment publiques. L'analogie la plus proche, à mon avis, est package-private En Java, mais cela ne fonctionne pas tout à fait lorsque j'organise ma bibliothèque dans des sous-espaces.

Par exemple, disons que j'ai une classe Service1 en racine et une autre classe Service2 Dans un sous-vue sous racine. J'aimerais Service1 Pour pouvoir faire référence à Service2 's Interface, mais de préférence pas faire Service2public comme cela exposerait Service2 Interface à l'extérieur du colis, ce qui n'est pas ce que j'ai l'intention.

J'imagine que ce n'est pas terriblement compliqué, mais je suis un peu confus sur la manière d'autoriser les forfaits de la soeur/parent d'accéder aux classes de sous-vue sans les faire public. La seule solution que j'ai pu vraiment penser est de tout) 1) mettre tout au même niveau de colis qui me permettrait d'utiliser package-private Pour cacher tout ce qui ne devrait pas être accessible au public mais est extrêmement désordonné ou 2) le sucer et faire mes interfaces publiques, qui offensent catégoriquement mes sensibilités.

Comment est-ce normalement fait? Toutes les classes sont-elles dans le même paquet, mais éventuellement organisées par des sous-répertoires? Je n'ai pas encore abordé une approche que j'aime vraiment.

6
JosephRT

En Java, votre surface de l'API prévue doit définir votre structure de colis. Évitez la tentation de créer des sous-packages juste pour "organiser" vos fichiers d'une manière qui ne concerne pas directement votre conception de l'API. La nécessité perçue de le faire peut même indiquer à la mauvaise conception de l'API.

Dans cet esprit, vous voudrez peut-être toujours utiliser un sous-vue pour créer une API interne. Par exemple, un groupe de classes peut vouloir que certains membres soient accessibles à d'autres classes du groupe, mais ne pas exposer ces membres au reste de votre bibliothèque. Dans ce cas, mettez-les dans un sous-vue et profitez de l'accès au paquet-privé. Vous devrez réfléchir attentivement si l'API exposée de la sous-vue est quelque chose que vous souhaitez concevoir, documenter et soutenir en tant que produit séparé. Cela rendra votre produit plus précieux, mais bien sûr à un coût pour vous. Si vous ne voulez pas prendre en charge l'API interne ou si vous n'êtes pas encore sûr, la solution habituelle consiste à mettre cette API dans un sous-vue avec un nom qui l'identifie comme interne, comme com.myproduct.internal, voire une hiérarchie de paquet entièrement différente, comme le com.Sun classes exposées par nécessité mais officiellement ne faisant pas partie de la norme Java API.

5
StackOverthrow

Cela peut ne pas s'appliquer à vous car je ne sais pas si Android le supporte, mais la principale caractéristique du Java Mise à jour est exactement sur ce problème.

La fonction de modules de Java 9 (connue sous le nom de jigsaw de projet) vous permet d'ajouter un fichier de métadonnées à un .jar qui (entre autres) répertorie les paquets visibles publiquement. Tous les autres Les paquets sont internes au module. En d'autres termes, les classes publiques à l'intérieur d'un module interne sont équivalentes aux classes internes dans un ensemble .NET.

5
Sebastian Redl

Je suis d'accord avec les autres réponses ici, que la norme Java Way est de ne pas créer de packages supplémentaires ni d'utiliser un appel de paquet interne. Je voulais signaler une autre option que vous avez avec Android.

Android a une annotation de support, RestrictTo. Toute personne utilisant le code annoté en dehors de la portée correcte obtient un avertissement de peluche.

https://developer.andrid.com/reference/andrroid/support/annotation/restrictto

Cela vous permettrait d'annoter des cours, des méthodes ou des champs comme étant limité à la bibliothèque elle-même.

@RestrictTo(RestrictTo.Scope.LIBRARY)

Il y a d'autres options pour la portée également. C'est le motif Google suivi avec la bibliothèque de support.

2
Michael Krussel

"Mais éventuellement organisé par des sous-répertoires" n'a aucun sens, car chaque sous-répertoire est un nouveau paquet en Java.

Ce qui est généralement fait, c'est documenter l'interface publique de l'emballage et les classes de mise en œuvre de documents comme étant ouvertes au changement, les utilisent directement à vos risques et périls.

Une façon dont vous pouvez également utiliser et que j'ai vu cela est utilisé efficacement, est divisé la bibliothèque en 2 fichiers JAR. Un fichier contenant les interfaces pour l'API publique uniquement et une seconde contenant tout le reste. Fournissez une documentation suffisante pour les interfaces et à côté de Aucun pour les classes de mise en œuvre, dans la version que vous publiez au public.

Et placez une certaine confiance dans vos utilisateurs. Faites-leur confiance pour coller à votre API publique, la plupart des volontés si c'est assez bien conçu, il n'est pas nécessaire de gâcher directement avec les internes directement, simplement parce que de jouer avec vos internes ferait leur propre travail beaucoup plus fragile.

1
jwenting