Hier ist mein Problem, mit dem ich jetzt konfrontiert bin. Ich habe eine Klasse, sagen wir Foo
. Diese Klasse definiert eine Methode namens getBar
, die eine Bar
-Instanz zurückgibt. Die Klasse Bar
ist in Foo
definiert und wird als public static final
deklariert. Ich möchte eine Klasse MyFoo
definieren, die Foo
erweitert. Ich möchte jedoch Bar
um MyBar
erweitern, indem ich meine eigenen Funktionalitäten (Methoden, Eigenschaften usw.) hinzufüge. .__ Ich möchte auch, dass getBar
MyBar
zurückgibt.
Das Problem ist Bar
ist endgültig. Hier ist ein Beispiel dafür, was ich machen möchte:
public class Foo {
Bar bar = new Bar();
public Bar getBar(){
return bar;
}
....
public static final class Bar {
}
}
Was ich tun möchte ist:
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
}
}
Wie kann ich das erreichen?
[EDIT] Ich füge meiner Frage weitere Details hinzu. Ich entwickle gerade ein Plugin für Jenkins und nach der Suche wird mir klar, dass es ein Plugin gibt, das die Basisfunktionen bietet, die ich machen möchte, Foo
und Bar
. Ich möchte Foo
und Bar
anpassen, damit es meinen Bedürfnissen entspricht. Foo ist die Hauptklasse des Plugins und erweitert eine Klasse namens Builder. Foo definiert eine Methode namens perform
, die alle Vorgänge zum Ausführen eines Builds enthält. Bar
enthält Operationen für Konfigurationszwecke und Foo benötigt eine Bar, um diese Informationen abzurufen.
Ich möchte also Foo um MyFoo
erweitern und einige Konfigurationen mit MyBar
hinzufügen. Und wie Sie sehen, muss MyFoo
diese Konfigurationen abrufen, indem Sie getBar();
aufrufen.
Zweitens habe ich keine Kontrolle über die Instanziierung von MyFoo
und MyBar
Was mich blockiert, ist, dass ich Bar nicht verlängern kann. Wie kann ich das erreichen?
Das kannst du nicht. Es sieht aus wie der Entwickler, der Bar
entworfen hat, damit er nicht erweitert werden kann - Sie können ihn also nicht erweitern. Sie müssen nach einem anderen Design suchen - möglicherweise nach einem, bei dem Vererbung nicht so häufig verwendet wird ... vorausgesetzt, Sie können den vorhandenen Code natürlich nicht ändern.
(Es ist schwer, konkrete Ratschläge zu geben, ohne mehr über das eigentliche Ziel zu erfahren - die Gestaltung des Gesamtsystems.)
Eine Klasse, die als final
deklariert ist, kann nicht erweitert werden. Sie können jedoch eine Zwischenklasse mit dem Namen Wrapper
erstellen. Dieser Wrapper enthält im Wesentlichen eine Instanz der ursprünglichen Klasse und stellt alternative Methoden zur Verfügung, um den Status des Objekts entsprechend dem gewünschten Vorgang zu ändern.
Natürlich haben Sie keinen Zugriff auf die privaten und geschützten Felder der final
-Klasse. Sie können jedoch die Methoden für Getter und Setter in Kombination mit den neuen Methoden und Feldern verwenden, die Sie in der Wrapper
-Klasse angegeben haben, um das gewünschte Ergebnis zu erhalten etwas relativ nah.
Eine andere Lösung besteht darin, final
keine Klasse zu deklarieren, wenn es keinen triftigen Grund dafür gibt.
Sie können eine final
-Klasse nicht erweitern. Dies ist der Zweck des final
-Schlüsselworts.
Es gibt jedoch (mindestens) zwei Problemumgehungen:
Abschlussklassen können nicht erweitert werden. Dies ist der Punkt, bei dem Klassen als endgültig deklariert werden. Sie können eine Schnittstelle definieren, von der sowohl die letzte Klasse als auch eine Wrapper-Klasse erben, die Aufrufe an die umschlossene letzte Klasse delegiert. Die Frage ist dann, warum die Klasse an erster Stelle finalisiert werden soll.
Wahrscheinlich möchten Sie einen Proxy. Es ist einfach zu implementieren. Dies ist ein großartiger Artikel: http://Java.dzone.com/articles/power-proxies-Java
Wenn einige Schnittstellen implementiert werden, könnte Decorator Design Pattern das Problem lösen.
Zum Beispiel können wir keinen StringBuffer in der TreeSet-Collection hinzufügen, da TreeSet nicht untergeordnetes Element des Interface Comparable ist:
public class Main(){
public static void main(String[] args){
TreeSet treeSetSB = new TreeSet();
treeSetSB.add(new StringBuffer("A")); //error, Comparable is not implemented
}
Wir können aber einen Wrapper verwenden, um die Comparable zu implementieren:
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);
}