2013-04-26 5 views
5

Я использую шаблон делегирования для обертывания объекта, созданного фабрикой в ​​сторонней библиотеке. Недавно библиотека добавила защищенный метод в базовый класс, и мой класс-оболочка больше не работает. Кто-нибудь имеет хорошее решение, не прибегая к размышлениям?Java: шаблон делегирования и защищенные методы

Это в 3-й партии библиотеки и в их пакете,

public class Base { 
    public void foo(); 

    protected void bar(); // Newly added 
} 

Это в моем собственном пакете,

public class MyWrapper extends Base { 
    private Base delegate; 

    public MyWrapper(Base delegate) { 
     this.delegate = delegate; 
    } 

    public void foo() { 
     delegate.foo() 
    } 

    protected void bar() { 
     // Don't know what to do 
    } 
} 

EDIT: Мой оригинальный пост не было ясно. Эти 2 класса находятся в разных пакетах.

Чтобы ответить на вопрос, почему мне нужна делегация. Это типичный пример использования шаблона Delegation/Wrapper, и я не могу показать его здесь в нескольких строках кода. Библиотека предоставляет базовый класс, но фактический объект с их фабрики является производным классом Base. Фактический класс изменяется в зависимости от конфигурации. Поэтому я не знаю, что такое делегат. Поэтому прямой шаблон наследования здесь не работает.

+0

Ну, в чем же цель этого метода? Можете ли вы просто проигнорировать это? Думаю, нет, поскольку вы заявляете «больше не работает» ... можете ли вы назвать super.bar()? Просто выстрел в синий цвет ... У вас есть какой-либо документ по этому новому методу? – Fildor

+0

Вы пытались переместить свой класс-оболочку в пакет с тем же именем/путем, что и у базового класса? это скорее взлом, чем решение, но методы 'protected' должны быть доступны в одном пакете. –

+1

. Методы базового класса' 'foo()' и 'bar()' выглядят так, как будто «Base» были интерфейсом или абстрактным классом. Не могли бы вы указать свой вопрос? Каким образом вам нужно размышление? Поскольку он защищен, вам может не потребоваться его переопределение. –

ответ

4
Access Levels 
Modifier Class Package Subclass World 
public  Y   Y  Y   Y 
protected Y   Y  Y   N 
no modifier Y   Y  N   N 
private  Y   N  N   N 

protected имеет package доступ тоже, видите ли вы какие-либо конкретные проблемы с этим:

class Base { 
     public void foo(){}; 

     protected void bar(){}; // Newly added 
    } 

    class MyWrapper { 
     private Base delegate; 

     public MyWrapper(Base delegate) { 
      this.delegate = delegate; 
     } 

     public void foo() { 
      delegate.foo(); 
     } 

     protected void bar() { 
      // Don't know what to do 
      delegate.bar(); //since its in same package, it can be referenced, do you expect compile time error? 
     } 
    } 

Далее, используя шаблон доверителю, почему класс-оболочка расширяет Base класс, я не вижу особой необходимости, так как вы уже есть экземпляр Base. Для меня это выглядит скорее декоратором.

+0

Звучит разумно –

+0

Базовый класс находится в сторонней библиотеке. Мой класс находится в другом пакете. –

+0

@ZZCoder вы можете создать ту же структуру пакета в своей собственной библиотеке, а затем ваш класс-оболочка будет в пакете _same_ как в классе «Base», это своего рода хак, и это будет вводить в заблуждение клиентский код вашей обертки , но, по крайней мере, это даст вам доступ к этому защищенному методу. Вот что я имел в виду в своем первом комментарии. –

1

Вам не нужен (или не должен?) Делегировать этот метод штриховки.

Если библиотека определила защищенный метод. Он не хочет, чтобы пользователь (конечно, в другом пакете) вызывал этот метод, за исключением создания подкласса этого типа. Вы пытаетесь нарушить правило.

Если вы хотите сделать это, есть способ, вы создаете подтип Base, скажете SubBase, вы создаете объект SubBase вместо Base, а затем передать subBase вашей обертке. то вы могли бы в вашей обертке bar() метода написать delegate.bar() В Таким образом, SubBase на самом деле делегат, или сказать, что ваша обертка делегирования SubBase не Base

Я думаю, вы знаете, что я имею в виду, так что я просто не набирайте пример кодов, только эта строка, я предполагаю, что это достаточно:

//Wrapper 

private SubBase delegate; 

вы видите обертка не нужно больше, если у вас есть SubBase. Вы даже можете определить public void pubBar() в своем SubBase, и там вы звоните this.bar(). таким образом, все объекты SubBase имеют доступ к защищенному методу (via pubBar()), независимо от того, из какого пакета

+0

dovoter, pls дают причину – Kent

1

Создается впечатление, что класс Base является либо интерфейсом, либо абстрактным классом. Если да, то вы должны реализовать метод bar(), например, используя любой из трех методов, перечисленных ниже.

Примечание стороны, если Base нормальный класс, вы не должны делать что-либо (вызов к экземпляру MyWrapper.bar() будет на самом деле приведет к вызову Base.bar().


Делегат родительского объекта

Это, как правило, хорошая идея, если метод bar() используется в качестве обратного вызова в 3-й партии API:

@Override 
protected void bar() { 
    delegate.bar(); 
} 

ничего не делать

Просто добавили пустой метод, чтобы избежать ошибок компиляции:

@Override 
protected void bar() { 
    // silently ignored 
} 

Бросьте исключение

Насильно предотвратить любое использование нового метод:

@Override 
protected void bar() { 
    throw new UnsupportedOperationException("not implemented"); 
} 

В качестве примечания, более прочная конструкция предпочитает composition over inheritance разъединить свою реализацию от реализации 3-й партии, например,

public class MyWrapper { // does not extend Base 
    private Base delegate; 

    public MyWrapper(Base delegate) { 
     this.delegate = delegate; 
    } 

    public void foo() { 
     delegate.foo() 
    } 

    // does not have to implement bar() 
} 
+0

Значит, вы тоже говорите, что он не должен делегировать «бар»-метод, правильно? В вашем примере у него не было бы выбора в любом случае. – Fildor

+0

@Fildor @ZZCoder Смотрите мое обновление. Поскольку класс 'MyWrapper' наследуется от' Base', он * должен * реализовать метод 'bar()', если 'Base' является абстрактным классом или интерфейсом. – matsev

+0

Нужно ли расширять 'Base'? Если нет, я бы пошел на упаковку matsev, которая избегает наследования. Если да, то все ваши клиенты не знают, что упираются в новый метод, верно? И я думаю, вы не ставите ссылку на него в стороннюю библиотеку ... так что в этом случае я бы просто реализовал пустой «манекен». – Fildor

0

Я использую Spring для инъекций в обертке в «Базовый делегат» из другого модуля и для получения делегата я использую Pojo завод.

<bean id="interfaceDelegate" factory-bean="DelegatePojoFactory" 
    factory-method="getMyDelegateInstance"> 
    <constructor-arg index="0"> 
     <value>OnLine</value> 
    </constructor-arg> 
</bean> 

<bean id="wrapper" class="path.Wrapper"> 
     <property name="delegate" ref="interfaceDelegate"></property> 
</bean> 
0

Если вам не нужен ваш доверитель быть фактическим экземпляром базового класса, вы можете просто удалить эту связь:

public class MyWrapper { 
    private Base delegate; 

    public MyWrapper(Base delegate) { 
     this.delegate = delegate; 
    } 

    public void foo() { 
     delegate.foo() 
    } 

} 

Независимо от того, что работает для вас очень сильно зависит от ваших других код и ваши потребности не совсем понятны мне прямо сейчас.

Если библиотека определяет интерфейс, предоставляющий общедоступный метод, который реализуется абстрактным базовым классом, вы можете разумно реализовать этот интерфейс, не наследуя от абстрактного базового класса, который также может удовлетворить ваши потребности.

Смежные вопросы