4

Я создаю класс, который переопределяет подпись метода, стирание которой идентично между двумя реализованными интерфейсами, но с незначительной разницей в отношении общего типа (один - тип, определяемый методом, другой - тип предполагаемого класса). Я ищу аккуратное решение. Я МОГУ ТОЛЬКО отредактировать унаследованный класс, а не оригинальные устаревшие интерфейсы.Название Clash, override fail, класс, реализующий два интерфейса с тем же стиранием

Чтобы показать случай, я сделал абстрактный образец, чтобы понять проблему:

Я получил Разработчик наследства родительского класса:

public class Developer<C>{ 
    Rate<C> getRate(Taxes<C> tax){ /*...*/ }  
} 

Я также получил арендуемый унаследованный интерфейс, с почти идентичная подпись

public interface Rentable { 
    <C> Rate<C> getRate(Taxes<C> taxes); 
} 

Как разработчик не арендуемый, в моей модели, я создаю специальный разработчика, который является одновременно девелоперым и Арендуемый материал.

public class OutsourcableDeveloper<C> 
       extends Developer<C> 
       implements Rentable{ 
    @Override 
    public Rate<C> getRate(Taxes<C> taxes){ /*...*/} 
} 

, а затем я получил печально известное

Имени столкновения: Метод getRate (Developer.Taxes) типа OutsourcableDeveloper имеет то же стирание как getRate (Developer.Taxes) типа, но Арендуемый не отменяет его

Как я могу избавиться от него, так OutsourcableDeveloper.getRate() скрывает как разработчик и арендуемое. getRate()?

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

Действительно ли имеет значение тот факт, что один из супертипов вводит тип метода, а другой из класса специально, когда я не собираюсь называть супер в моей реализации? Может быть, есть трюк, чтобы преодолеть проблему, учитывая это упрощение?

EDIT: Я открыл более абстрактную, менее ориентированные на конкретные решения в мою актуальную проблему, вопрос для обсуждения проблемы проектирования наследования, который я считаю это коррелированной сущность фактического вопроса у меня возникли: Why can't I extend an interface "generic method" and narrow its type to my inherited interface "class generic"?

edit2 : Предыдущий вопрос привел меня к ответу, размещенному здесь

ответ

0

Хорошо, я нашел способ решить эту проблему. Это clumpsy, но это проще один, если архитектура не очень сложна, вдохновленные моим Why can't I extend an interface "generic method" and narrow its type to my inherited interface "class generic"? собственный ответ:

public class OutsourcableDeveloper<C> 
       extends Developer<C> 
       implements Rentable{ 

    /* This might not be needed if we don't need to extract C from taxes parameter */ 
    final Class<C> currencyClass; 
    public OutsourcableDeveloper(Class<C> currencyClass){ this.currencyClass = currencyClass;} 

    @Override 
    public Rate<C> getRate(@SuppressWarnings("rawtypes") Taxes taxes){ 
     try{ 
      C taxesCurrency = (C) currencyClass.cast(taxes.getCurrency()); //IF actually needed getting the typed instance 
      return new Rate<C>(taxesCurrency); //Or whatever processing 
     } catch (ClassCastException e){ 
      throw new UnsupportedOperationException("OutsourcableDeveloper does not accept taxes in a currency that its not hims"); 
     } 
    } 
} 

Также можно играть с «расширяет Developer» без универсального типа, так что неявно в сыром виде. но мы теряем печатать для неконфликтующих методов, а также

2

Ну, они на самом деле не равны. Поскольку любой объект Rentable-Instance позволяет задавать любой типовой параметр T, в то время как OutsourcableDeveloper ограничивает его.

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

<C> Rate<C> getRate(Taxes<C> taxes); 

версии интерфейса. Но ожидайте, насколько запутан разработчик, если он захочет подкласса OutsourceableDeveloper. Из определения разработчика он может предположить, что метод getRate зафиксирован на C, но на самом деле он может внезапно принять любое значение. -> позволяя это приведет к путанице.

Что я могу вам предложить, это следующий пример кода, который может быть подходящим для вашего случая. Хотя определенно будет неудобно использовать его.Но поскольку вы пересылаете все методы в OursourcableDeveloperRentable, это возможно. Комментарии должны объяснить, как это работает.

//This class itself can be added to any Developer-lists 
public class OutsourcableDeveloper<C> extends Developer<C> { 

    public final OutSourcableDeveloperRentable RENTABLE_INSTANCE = new OutSourcableDeveloperRentable(); 

    @Override 
    public Rate<C> getRate(final Taxes<C> taxes) { 
     // Simply forward to the more general getRate instance. 
     return this.RENTABLE_INSTANCE.getRate(taxes); 
    } 

    public void exampleBehaviourA() { 
     //Example for how you can make both objects behave equally. 
    } 

    // This class can be added to the lists requiring a Rentable 
    // And the original value can be retrieved by both classes. 
    public class OutSourcableDeveloperRentable implements Rentable { 

     public final OutsourcableDeveloper<C> PARENT_INSTANCE = OutsourcableDeveloper.this; 

     //This method is the one to implement because it is more general than 
     //the version of OutsourcableDeveloper. 
     @Override 
     public <T> Rate<T> getRate(final Taxes<T> taxes) { 
      // Do your work. 
      return null; 
     } 

     public void exampleBehaviourA() { 
      //Just an example - Maybe for you it makes for sence to 
      //forward the method of Oursoursable-Developer to here. 
      //Then all Behaviour would be found in this class. 
      OutsourcableDeveloper.this.exampleBehaviourA(); 
     } 

    } 
} 
+0

Хороший ответ спасибо (я подожду, чтобы увидеть, есть ли что-нибудь более сложное или простое) !! BTW, если я не могу либо выбрать ограниченную по методу версию метода в моем дочернем элементе, столкновение имен: метод getRate (Developer.Taxes ) типа OutsourcableDeveloper имеет то же стирание, что и getRate (Developer.Taxes ) типа Разработчик , но не переопределяет его – Whimusical

+0

И, на мой взгляд, рационального для такого поведения нет, компилятор должен обеспечить более строгое из двух. Я реализую один и тот же метод, в одном интерфейсе тип *, а в другом должен быть тем же классом, поэтому в случае, если вы реализуете оба варианта, ограниченный класс может быть прозрачным, без нарушения какой-либо некогерентности, я считаю. – Whimusical

+0

Это невозможно. Вызывающий интерфейс ожидает, что любые параметры будут разрешены. Если вы ограничите их программированием, вы портите намерение ООП. –

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