2009-10-01 7 views
4

Ce que je veux vraiment, c'est une classe avec un constructeur générique, et quand un constructeur identique à une sous-classe est invoqué, la sous-classe aura accès aux mêmes champs. Voici un exemple de ce que je voudrais faire:Classe Java dont les champs ne sont accessibles qu'à ses sous-classes (sans getters/setters)?

public abstract class Command{ 
    private Mediator m 

    public Command(Mediator med){ 
     m = med; 
    } 

    abstract void exec(); 
} 

public class FoobarCommand extends Command{ 
    public FoobarCommand(Mediator med){ 
     super(med); 
    } 

    public void exec(){ 
     med.doAFoobar() 
    } 
} 

public static void main(String[] args){ 
    Mediator m = new Mediator(); 
    Command c = new FoobarCommand(m); 
    c.exec(); 
} 

Évidemment, cela ne fonctionnera pas parce que FoobarCommand n'a pas accès direct au médiateur med. Alors, comment auriez-vous accès au champ med? Je ne veux pas que quelqu'un d'autre que les sous-classes y aient accès, et "protected" n'est pas une option parce que je veux que les gens puissent créer leurs propres commandes (qui seraient évidemment en dehors du paquet).

+0

Je ne comprends pas la raison pour laquelle vous avez pré-protégé pas beng une option –

+2

Il semble que ce problème est causé par "exec" étant une méthode du commandant pas le médiateur. Pourquoi ne pas avoir la fonctionnalité d'exec comme une méthode du Mediator (déclarée comme faisant partie d'une interface de Mediator)? Ensuite, vous pourriez avoir un objet Command à usage général avec un setter pour le Mediator et une méthode exec polymorphe. –

+1

Merci pour tous les commentaires tout le monde. J'ai été un peu privé de sommeil et j'ai réalisé que je voulais "protégé" tout au long, je n'aurais même pas dû poser la question: -! – Jay

Répondre

12

Il n'y a actuellement aucun modificateur d'accès à proprement parler. Il est impossible de déclarer un champ (ou une méthode/classe, d'ailleurs) seulement accessible aux sous-classes; le modificateur le plus restrictif que vous pouvez utiliser est protected, qui permet toujours d'accéder à d'autres classes dans le package de la classe parente.

Mais à part ce problème, protected est le chemin à parcourir.

Modifier: pour préciser que protégé est une option. Pour accéder à une méthode protégée, vous devez être soit une sous-classe ou dans le même package; vous n'avez pas besoin d'être les deux. Donc, une sous-classe de Command créée dans un package différent serait toujours en mesure d'accéder à (super).m.

+0

Vous pouvez vérifier le type dans les getters et les setters. Ce n'est pas un modificateur d'accès, mais il devrait tout de même atteindre le résultat souhaité. –

5

Déclarer Mediator Med comme "protégé" pas privé.

2

Vous devez déclarer Mediator m protégé dans votre classe mère.

De plus, dans la méthode exec() de votre sous-classe, vous devez faire m.doAFoobar() au lieu de med.doAFoobar() puisque med n'est pas un membre mais un paramètre formel de votre constructeur.

1
abstract class Command { 
    protected Mediator m 

    public Command(Mediator med){ 
     m = med; 
    } 

    abstract void exec(); 
} 

La classe n'est pas public, il ne peut être prolongée par d'autres classes dans le même paquet et « m » est protégé de sorte qu'il est accessible par les classes dérivées.

+0

Oui mais peut également être accédé par des classes du même paquet et ci-dessus, ce qui n'est pas un comportement recherché. – EliuX

1

Si vous voulez un champ soit accessible uniquement à la classe elle-même et toutes les classes dérivées et d'autres classes de ce package, utilisez le mot-clé protégé. C'est ce qu'il est là pour, et il devrait encore fonctionner même en dehors du paquet. Au lieu de les appeler med.doFoobar(), ils doivent appeler m.doFoobar();

Alternativement, vous pouvez créer une fonction d'accès protégée (ou publique, même). De cette façon, vous exposer la possibilité d'obtenir le médiateur, mais vous ne devez pas les laisser l'écraser après qu'il a été déclaré. Cependant, ce que vous voulez (impossible d'être lu à l'intérieur du paquet) est impossible dans l'encodage Java. Mais, puisque vous êtes celui qui écrit ce paquet particulier, ne pourriez-vous pas y accéder depuis l'intérieur du paquet? Ou créer votre propre paquet avec juste ce fichier? Il n'y a aucun moyen d'autoriser l'accès aux sous-classes et de ne pas autoriser les classes dans le paquet.

+1

vous ne pouvez pas le rendre accessible aux sous-classes SEULEMENT. Il sera également visible pour les classes dans le même paquet. – user101884

+0

Point, je vais modifier ma réponse. – DivineWolfwood

0

Ce que vous pouvez faire est de donner la sous-classe une variable qui est nommé exactement la même chose, puis réglez-égale à la superclasse en utilisant des constructeurs et des méthodes comme

public abstract class Command{ 
    private Mediator m 

    public Command(Mediator med){ 
     m = med; 
    } 

    abstract void exec(); 
} 

public class FoobarCommand extends Command{ 

    private Mediator m; 

    public FoobarCommand(Mediator med){ 
     super(med); 
     m = med; 
    } 

    public void exec(){ 
     m.doAFoobar() 
    } 
} 

public static void main(String[] args){ 
    Mediator m = new Mediator(); 
    Command c = new FoobarCommand(m); 
    c.exec(); 
} 

Cependant, cela est limité dans ce qu'il peut faire. Comme m est une référence d'objet, les changements à m dans la sous-classe seront reflétés dans la superclasse; cependant, cela ne se produirait pas si le membre de la classe était une primitive. (Etant donné que toutes les primitives ont un objet équivalent, cela peut être contourné si légèrement maladroit)

La sous-classe doit également recevoir directement la référence, car c'est là qu'une copie de la référence est stockée. Pour les superclasses abstraites, c'est très bien, car une sous-classe est garantie, mais en dessous, vous devez faire attention à la façon dont vous gérez les données.

Questions connexes