Method that returns different types?

Refresh

December 2018

Views

94 time

3

I'm writing a method.

This is the Hierarchy tree:

IProtocoll
|
|--ProtocolImpl1
|
|--ProtocolImpl2
|
|--ProtocolImpl3

The method itself looks like this:

public static List<IProtocol> getProtocolsByType(String type, Transaction trx) {
    Iterator<IProtocol> protocols = trx.getProtocols();
    List<IProtocol> protocolsList = new ArrayList<IProtocol>();
    while (protocols.hasNext()) {
        if (StringHeper.isEqual(protocolls.next().getProtocolType(), type) {
            protocolsList.add(protocolls.next());
        }
    }
    return protocolsList
}

And the usage example.

List<IProtocol> list = ProtocolHelper.getrProtocolsByType("PROTOCOL1", trx)

for (IProtocol protocol : list) {
    ProtocolHelper.createProtocolType1((ProtocolImpl1) protocol)
}

Now - as seen in the type hierarchy - there are 3 possibilities of what this method could return.

String type is defining what type of protocols shall be returned. trx.getProtocols() will return an Iterator containing ALL 3 types of protocol.

Is there a way of somehow unifying this method that it will return one of those 3 types, without using unnecessary casting later while using that method?

5 answers

0

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

List<ProtocolImpl1> list = (List<ProtocolImpl1>) ProtocolHelper.getProtocolsByType("PROTOCOL1", trx)

for (ProtocolImpl1 protocol : list) {
    ProtocolHelper.createProtocolType1(protocol)
}

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

List<ProtocolImpl1> getAllProtocolsOfType1(trx);
List<ProtocolImpl2> getAllProtocolsOfType2(trx);
List<ProtocolImpl3> getAllProtocolsOfType3(trx);

Но, конечно, это не очень масштабируемым, если количество протоколов растет.

0

Попробуйте использовать Java дженериков. public static <T extends IProtocol> List<T> getProtocolsByType Тип Т может быть любого типа , который проходит IProtocol. Посмотрите на гадательных учебники о них -> https://docs.oracle.com/javase/tutorial/java/generics/ Они будут решить вашу проблему.

6

Вы можете попробовать следующее:

public static <T extends IProtocol> List<T> getProtocolsByType(Class<T> typeClass, Transaction trx) {    
  Iterator<IProtocol> protocols = trx.getProtocols();
  List<T> protocolsList = new ArrayList<T>();
  while( protocols.hasNext() ) {
     //call next() only once
     IProtocol p = protocols.next();

     //Check if p is an instance of typeClass or a subtype
     if ( typeClass.isAssignableFrom( p.getClass() ) {
        protocolsList.add( (T)p );
     }
   }
   return protocolsList;
}

List<ProtocolImpl1> list = ProtocolHelper.getrProtocolsByType( ProtocolImpl1.class, trx)

Поэтому вместо передачи типа в виде строки вы бы пройти класс реализации, который вы хотите получить.

Бросок (T)pнеобходим , но так как вы проверяете для pтого типа Tили подтипа это безопасно.

1

Вот одно из возможных решений:

public <I extends IProtocol> List<I> getProtocols(Class<I> protocolClass) {
    Iterator<IProtocol> protocols = trx.getProtocols();
    List<I> protocolsList = new ArrayList<I>();
    while (protocols.hasNext()) {
      if (protocols.next().getClass().equals(protocolClass)) {
          protocolsList.add((I) protocols.next());
      }
    }
    return protocolsList;

}

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

Единственная проблема состоит в том, что приведение к I вызывает предупреждение, но так как мы уже проверили тип класса, мы знаем, что это будет отбрасывать OK.

2

Дженерики является спасителем. Используйте что-то вроде этого:

public static <T extends IProtocol> List<IProtocol> getProtocolsByType(Class<T> clazz, Transaction transaction) {    
  //do logic here
}