Voici mon problème en fait je suis confronté maintenant. J'ai une classe, disons Foo
et cette classe définit une méthode appelée getBar
qui renvoie une instance Bar
. La classe Bar
est définie dans Foo
et et est déclarée public static final
. Ce que je veux faire, c'est définir une classe MyFoo
qui étend Foo
mais je veux aussi étendre Bar
avec MyBar
en ajoutant mes propres fonctionnalités (méthodes, propriétés, etc.). Je veux aussi que getBar
renvoie MyBar
.
Le problème est Bar
est final. Voici une illustration de ce que je veux faire:
public class Foo {
Bar bar = new Bar();
public Bar getBar(){
return bar;
}
....
public static final class Bar {
}
}
Ce que je veux faire c'est:
public class MyFoo extends Foo {
public MyBar getBar(){ // here I want to return an instance of MyBar
}
public static final class MyBar extends Bar { // That's impossible since Bar is final
}
}
Comment puis-je y arriver?
[EDIT] J'ajoute plus de détails à ma question. Je développe actuellement un plugin pour Jenkins et, après une recherche, je me rends compte qu’il existe un plug-in qui offre les fonctionnalités de base que je souhaite utiliser, Foo
et Bar
. Je veux personnaliser Foo
et Bar
, afin que cela corresponde à mes besoins. Foo est la classe principale du plugin et étend une classe appelée Builder. Foo définit une méthode appelée perform
qui contient toutes les opérations permettant d'effectuer une construction. Bar
contient des opérations de configuration et Foo a besoin de Bar pour obtenir ces informations.
Donc, ce que je veux faire, c'est étendre Foo avec MyFoo
et ajouter quelques configurations avec MyBar
. Et comme vous le voyez, MyFoo
devra obtenir ces configurations en appelant getBar();
La deuxième chose est que je n’ai aucun contrôle sur l’instanciation de MyFoo
et MyBar
Ce qui me bloque, c'est que je ne peux pas prolonger Bar. Comment puis-je y arriver?
Vous ne pouvez pas, fondamentalement. Cela ressemble au développeur qui a conçu Bar
pour qu'il ne soit pas étendu - vous ne pouvez donc pas l'étendre. Vous devrez rechercher un modèle différent - peut-être un modèle qui utilise moins l'héritage ... en supposant que vous ne pouvez pas modifier le code existant, bien sûr.
(Il est difficile de donner des conseils plus concrets sans en savoir plus sur le véritable objectif - la conception du système global.)
Vous ne pouvez pas étendre une classe déclarée final
. Cependant, vous pouvez créer une classe intermédiaire, appelée Wrapper
. Cet encapsuleur contiendra essentiellement une instance de la classe d'origine et fournira des méthodes alternatives pour modifier l'état de l'objet en fonction de ce que vous souhaitez faire.
Bien sûr, cela ne donnera pas accès aux champs privés et protégés de la classe final
, mais vous pouvez utiliser ses méthodes d’obtention et de réglage, combinées aux nouvelles méthodes et champs que vous avez déclarés dans la classe Wrapper
pour obtenir le résultat souhaité, ou quelque chose de relativement proche.
Une autre solution consiste à ne pas déclarer une classe final
s'il n'existe aucune raison valable de le faire.
Vous ne pouvez pas étendre une classe final
- c'est le but du mot clé final
.
Cependant, il y a (au moins) deux solutions:
Vous ne pouvez pas étendre les classes finales, c'est le point de déclarer des classes finales. Vous pouvez définir une interface dont la classe finale hérite et une classe wrapper qui délègue les appels à la classe finale encapsulée. La question est alors pourquoi rendre la classe finale en première place.
Probablement ce que vous voulez, c'est un proxy. C'est facile à mettre en œuvre. C'est un excellent article: http://Java.dzone.com/articles/power-proxies-Java
S'il implémente des interfaces, Motif de conception de décorateur pourrait résoudre le problème.
Par exemple, nous ne pouvons pas ajouter de StringBuffer dans la collection TreeSet, car TreeSet n'est pas l'enfant de l'interface comparable:
public class Main(){
public static void main(String[] args){
TreeSet treeSetSB = new TreeSet();
treeSetSB.add(new StringBuffer("A")); //error, Comparable is not implemented
}
Mais nous pouvons utiliser un wrapper pour implémenter le Comparable:
class myWrap implements Comparable{
TreeSet treeset;
public myWrap() {
this.treeset=new TreeSet<>();
}
public TreeSet getTreeset() {
return treeset;
}
public void setTreeset(TreeSet treeset) {
this.treeset = treeset;
}
}
public class Main(){
public static void main(String[] args){
myWrap myWrap =new myWrap();
TreeSet myTrs =myWrap.getTreeset();
myTrs.add("b"); // no error anymore
myTrs.add("a");
myTrs.add("A");
System.out.println(myTrs);
}