Вопрос
Я работаю со сторонней платформой, и оказалось, что мне нужно обернуть некоторые ее объекты в качестве делегата одного из моих классов.
class Foo { // 3rd party class.
protected void method() {}
}
class FooWrapper extends Foo {
private Foo mDelegate;
public FooWrapper(Foo inDelegate) {
mDelegate = inDelegate;
}
protected void method() {
mDelegate.method(); // error can't access protected method() of mDelegate
}
}
Итак, есть проблема.Мне нужно делегировать этот метод внутреннему объекту, но он защищен и, следовательно, недоступен.
Есть идеи о способах решения этой конкретной проблемы?Это для Java 1.3.
Решение
Почему вы создаете отдельный экземпляр Foo?FooWrapper уже является Foo.
class Foo {
protected void method() {}
}
class FooWrapper extends Foo {
protected void method() {
super.method();
}
}
Редактировать:если вам действительно нужен отдельный экземпляр, один из способов (хотя и немного некрасивый) — использовать отражение:
public class Foo {
protected void method() {
System.out.println("In Foo.method()");
}
}
public class FooWrapper extends Foo {
private Foo foo;
public FooWrapper(Foo foo) {
this.foo = foo;
}
public void method() {
try {
Method m = foo.getClass().getDeclaredMethod("method", null);
m.setAccessible(true);
m.invoke(foo, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Редактировать2: Основываясь на вашем комментарии ниже, создайте два подкласса Foo: один, который просто предоставляет общедоступные версии защищенных методов, и другой, который переопределяет все важные методы.Первый будет выглядеть и действовать точно так же, как Foo, второй может делать все, что вам нужно:
public class Foo {
protected void method() {
System.out.println("In Foo.method()");
}
}
public class DelegateFoo extends Foo {
public void method() {
super.method();
}
}
public class FooWrapper extends Foo {
private DelegateFoo foo;
public FooWrapper(DelegateFoo foo) {
this.foo = foo;
}
public void method() {
foo.method();
/* extra logic here */
}
}
Другие советы
Когда я оказался в такой ситуации, и это неприятно, но работает, это создать PublicFoo в том же пакете, что и Foo (но в вашем исходном коде), расширить Foo и переопределить protected метод и сделать его общедоступным.
Теперь FooWrapper может расширять PublicFoo и делать все, что вы захотите.
Однако обратите внимание: если исходный jar-файл подписан и запечатан, вам потребуется удалить подписи, прежде чем вы сможете его развернуть.(Вы можете зайти в каталог Manifest в банке и просто удалить сертификаты)
Что ж, если у него есть публичный доступ к его свойствам (будь то геттеры или общедоступные переменные), вы можете создать конструктор копирования:
public FooWrapper(Foo inDelegate) {
this.property1 = inDelegate.getProperty1();
this.property2 = inDelegate.getProperty2();
// for every property
}
Если свойства являются объектами...отлично, даже лучше, потому что тогда любые внесенные вами изменения будут отображаться и при доступе через исходный объект!(То есть до тех пор, пока вы не замените один из этих объектов, что необходимо для неизменяемых классов, таких как String.)
Подкласс должен иметь доступ к защищенным методам суперкласса.
Если вы просто вызовете super.method() вместо mDelegate.method(), все пройдет;вы оба оборачиваете родительский класс и создавая его экземпляр.