2009-04-08 9 views
4

J'ai un paquet avec unInterdisez extension directe de la classe Java en dehors de son paquet

public abstract class Player { /*...*/ } 

et ces

public abstract class GamePlayer extends Player { /*...*/ } 
public abstract class TournamentPlayer extends Player { /*...*/ } 
public abstract class StatelessPlayer extends Player { /*...*/ } 

Les utilisateurs du paquet besoin de joueurs, mais afin d'utiliser le paquet sans le casser Je demande qu'ils ne directement étendre le joueur. Au lieu de cela, ils devraient étendre l'une des sous-classes fournies. Question: Comment est-ce que je devrais empêcher des utilisateurs d'étendre le joueur directement?

Je suis à la recherche d'un moyen qui rend évident que cette interdiction est destinée.

Répondre

14

Faites en sorte que les constructeurs au Player aient un accès au package uniquement. Ensuite, ils ne pourront pas appeler le constructeur ou l'étendre eux-mêmes. Si vous n'avez pas déjà un constructeur explicite dans Player, créez-en un (sinon le compilateur créera un constructeur public sans paramètre par défaut).

(Notez que je ne l'ai suggéré de faire cela au constructeur . La classe elle-même peut être public afin que les clients peuvent toujours l'utiliser.)

Cela fonctionne parce que tout constructeur (autre que dans java.lang.Object) doit appeler un constructeur de superclasse (explicitement ou implicitement). S'il n'y a pas de constructeur accessible, vous ne pouvez pas créer la sous-classe.

+0

+1 pour la note sur le constructeur implicite public par défaut – Alnitak

-1

Utilisez le modificateur d'accès par défaut, également appelé accès "Package private". En d'autres termes, ne spécifiez pas un modificateur d'accès

abstract class Player { /*...*/ } 

Le documentation here at Sun's website décrit plus en détail tous les modificateurs d'accès.

+0

Mais les clients seront même en mesure de voir la classe? Désolé, je n'ai pas de javac à portée de main pour vérifier moi-même. – jjujuma

+0

Non, ils ne le feront pas - ce qui explique pourquoi ce ne devrait être que le constructeur qui n'est pas public. –

+0

hmm, bon point ... – Alnitak

9

Assurez-vous que les constructeurs du joueur ne sont pas publiques:

public abstract class Player { 
    Player() { 
     // initialization goes here 
    } 
} 

Puis les classes peuvent étendre Player à partir dans le même paquet, mais ne devrait pas être en mesure de l'extérieur de l'emballage.

+1

Et pas protégé non plus ... –

1

Um ... rendre la classe Player non publique? Il suffit de laisser "public", alors ce sera un paquetage privé, c'est-à-dire que seules les classes du même paquet peuvent l'étendre. Cependant, rien n'empêche carrément les gens de mettre leurs propres classes dans ce paquet. Je crois qu'il est possible de l'empêcher en le mettant dans un fichier JAR signé, puis toute tentative de chargement d'une classe non signée (ou signée différemment) dans le même paquet échouera.

+0

Je crois que cela empêche * use * en dehors du paquet ainsi que, pas seulement l'héritage. – Herms

0

Je recommande

  • créer des interfaces publiques pour les choses que vous voulez que les clients d'accéder, mais pas créer ou sous-classe
  • Créer des classes publiques pour les choses que vous voulez que les clients d'accéder et créer ou sous-classe
  • toute autre chose devrait être non publique

Le problème avec cette approche est que vous finissez avec tout needi Il s'agit d'être dans un seul paquet, ce qui est mauvais pour l'organisation à mesure que la bibliothèque se développe.

Pour permettre l'utilisation de plusieurs paquets avec protection, jetez un oeil à OSGi. OSGi vous permet de restreindre les paquets auxquels un bundle (jar) permet d'accéder à d'autres bundles, et même de configurer des bundles "friend" offrant une visibilité supplémentaire.

paquet comme protection unité de Java modèle ne suffit pas quand vous voulez vraiment protéger les bibliothèques qui obtiennent un grand ...

Questions connexes