2015-05-04 6 views
2

Скажем, у меня есть ситуация выглядит следующим образом:Используйте статический тип только получаемый во время выполнения

Класс X имеет поле s типа S.

S продлевается на два класса A и B и реализующих некоторые те же методы/поля, которые мы все знаем, то должны быть реализованы в S, но, к сожалению, это не так.

Теперь я хочу сделать что-то вроде этого:

"A or B" downcast_field; 
if(s instanceof A) 
    downcast_field = (A)s; 
else if (s instanceof B) 
    downcast_field = (B)s; 

//do something common for the two cases but that need methods implemented both in A and B 

Проблемы затем с заранее статическим типом (из-за IFs), что позволяет мне называть такие методы.

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

+0

Можете ли вы добавить интерфейс к 'A' и' B'? –

+0

Дизайн очень плохой человек!Вы должны изменить его – Pratik

+0

@pratik Я бы уже сделал это, если это возможно! К сожалению, на данный момент это должно остаться – Demplo

ответ

4

Если вы можете изменить A и B, то вы можете добавить один и тот же интерфейс к обоим. Это позволит вам присвоить этот тип downcast_field и вызвать методы.

Если вы не можете изменить A и B, то у вас есть два варианта:

  • Вы можете написать A2 и B2. Скопируйте код от A и B в новые типы. Это позволяет вам изменять код (если вы не можете управлять созданием этих типов). Кроме того, вы также можете создать S2, который расширяет S и размещает там общий код, а затем расширяет A2/B2.

  • Создайте интерфейс, а затем две реализации, которые просто делегируют вызовы реальному типу.

    В этом решении, вы можете

    Wrapper downcast_field; 
    if(s instanceof A) 
        downcast_field = new AWrapper((A)s); 
    else if (s instanceof B) 
        downcast_field = new BWrapper((B)s); 
    
    downcast_field.foo(); 
    

    Вы можете сделать два оберток продлить тот же тип и переместить общий код.

+0

Мне нравится использование делегирующего класса-оболочки, за исключением того факта, что он добавляет еще три класса с особым знанием 'A' и' B' для этой цели, что является своего рода неаккуратным. Учитывая сценарий, я думаю, что это в значительной степени лучшее доступное решение (отличное от материала на Java 8, но, скорее всего, вы не используете его ...) –

+0

Да, вы могли бы использовать ссылки на методы, замыкания или отражение. Ссылки должны быть быстрыми, закрытие должно быть ОК, отражение будет довольно медленным. –

+0

Расширение S с midClass было моей первоначальной идеей. В общем, я думаю, что в любом случае нет возможности для любого элегантного решения. Спасибо за горстку возможностей. @ShotgunNinja шансы были правильными, нет java8: - / – Demplo

3

Насколько я понимаю, ваша ситуация следующая:

public class S { 
} 

public class A extends S { 

    public void doSomething() { 
     System.out.println("A is doing something ..."); 
    } 
} 

public class B extends S { 

    public void doSomething() { 
     System.out.println("B is doing something ..."); 
    } 
} 

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

public interface WrapperInterface { 
    void doSomething(); 
} 

, то вы можете использовать это как так

public class Main { 

    public static void main(String[] args) { 
     WrapperInterface a=wrap(new A()); 
     WrapperInterface b=wrap(new B()); 

     a.doSomething(); 
     b.doSomething(); 
    } 

    private static WrapperInterface wrap(final S s) { 
     WrapperInterface downcast_field=null; 
     if (s instanceof A) 
      downcast_field = new WrapperInterface() { 
       @Override 
       public void doSomething() { 
        ((A) s).doSomething(); 
       } 
      }; 
     else if (s instanceof B) { 
      downcast_field = new WrapperInterface() { 
       @Override 
       public void doSomething() { 
        ((B) s).doSomething(); 
       } 
      }; 
     } 
     return downcast_field; 
    } 
} 

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

  • Нет связанных вопросов^_^