2010-12-07 2 views
4

Итак, после уклонения от Java, так как я ушел из Uni, это было навязано мне. Я пытаюсь реорганизовать некоторый код, и у меня есть большая часть того, где я хочу быть. К сожалению, я остался с одним куском хитроумного кода. На данный момент мне нужно бросить подкласс, но я уверен, что должен быть лучший способ. Если кто-то может помочь с этим лучшим способом, я был бы признателен.Понимание Java Generics - Это можно сделать лучше?

public abstract class Protocol { 
    protected Class<? extends ProtocolConfiguration> configClass; 

    public void open() { 
     ProtocolConfiguration config = HighAvailabilityConfiguration.create(configClass, this.getProtocolName()); 
     config = this.preprocessConfig(config); 
     // blah 

    } 

    protected ProtocolConfiguration preprocessConfig(ProtocolConfiguration protocolConfig) { 
     return protocolConfig; 
    } 
} 

public class InteractionProtocol extends Protocol { 
    public InteractionProtocol() { 
     this.configClass = InteractionProtocolConfiguration.class; 
    } 

    @Override 
    protected ProtocolConfiguration preprocessConfig(ProtocolConfiguration protocolConfig) { 
      // *** Is it possible to operate on protocolConfig as InteractionProtocolConfiguration without casting? *** 
      InteractionProtocolConfiguration config = (InteractionProtocolConfiguration) protocolConfig; 
      config.setClientName(ClientName); // does not exist on base class 
      return config; 
    }; 
} 

У меня есть несколько классов, расширяющих протокол. Каждый из них должен знать об их собственном конкретном классе ProtocolConfiguration. Причина в том, что у меня есть протокол ProtocolConfigurationFactory, который принимает тип класса для генерации в основном полных элементов конфигурации. Я не контролирую фабрику или классы конфигурации. Они отделены от библиотеки, которую я использую. Но открытие протокола является общим для всех протоколов, за исключением требования о настройке нескольких настраиваемых свойств в конфигурации для каждого подкласса.

Edit:

Для справки, я приведу код для HighAvailabilityConfiguration.create().

public static <T extends ProtocolConfiguration> T create(Class<T> clazz, String protocol) throws ConfigException { 
    T config; 
    try { 
     // get the constructor that only takes a String 
     @SuppressWarnings("unchecked") 
     Class<String>[] ctorArgs1 = new Class[1]; 
     ctorArgs1[0] = String.class; 
     Constructor<T> ctor = clazz.getDeclaredConstructor(ctorArgs1); 
     config = ctor.newInstance(protocol); 
    } catch (Exception e) { 
     Log.error(e); 
     throw new ConfigException("Could not create ProtocolConfiguration for " + protocol); 
    } 
    ... 
    return config; 
} 

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

ответ

5

У меня будет трещина. Я думаю, что это могло бы быть лучше (я просто печатаю это, это не тестировался!):

public abstract class Protocol<T extends ProtocolConfiguration> { 

    private Class<T> configClass; 

    public void open() { 
     T newConfig = HighAvailabilityConfiguration.create(configClass, this.getProtocolName()); 
     config = this.preprocessConfig(newConfig); 
    } 

    protected abstract T preprocessConfig(T protocolConfig); 
} 

Тогда вы можете сделать это:

public class InteractionProtocol extends Protocol<InteractionProtocolConfiguration> { 

    // Implementation of generic abstract method. 
    protected InteractionProtocolConfiguration preprocessConfig(InteractionProtocolConfiguration protocolConfig) { 
     protocolConfig.setClientName(ClientName); // does not exist on base class 
     return protocolConfig; 
    }; 
} 

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

+0

Это то, что я сейчас пытаюсь сделать. Проблема заключается в том, что this.getClass() в методе создания. Это должен быть T.class, но это запрещено. – 2010-12-07 06:57:27

+0

Я уже создавал класс в производном конструкторе. Я тоже пытался устранить это, но это не проблема, а хитрость. Я также пытался получить ссылку на подкласс в базовом классе, указав параметр «рекурсивные генерики» (не настоящее имя для него). Короткий ответ: это прекрасно работает, если я не пытаюсь перекомплементировать ситуацию. – 2010-12-07 07:02:20

1

Возможный вопрос - существует ли какая-либо конкретная причина для принятия обобщенной ссылки «configClass»? Это вполне может быть просто ссылкой ProtocolConfiguration.

Кроме того, поскольку вы упомянули, что операция setClientName доступна только в подклассе InteractionProtocolConfig, я рекомендую, что вы сделали правильный путь реализации логики. Тем не менее, оптимизация, которую вы можете сделать , вероятно, do должна иметь переменную экземпляра уровня подкласса, которая имеет тип InteractionProtocolConfig. После этого вы всегда можете использовать эту ссылку вместо того, чтобы сбрасывать переменную config везде, которую вы хотите использовать в подклассе.

Однако, если метод preProcessConfig - это единственное место, где вы сбиваете с толку, тогда не так много смысла в принятии вышеупомянутой стратегии.

+0

Я согласен и брожу о «обобщении» переменной-члена configClass и необходимости «набирать» весь класс протокола. – drozzy 2010-12-16 21:58:44

1

Вы не хотите this.getClass() здесь:

T newConfig = (T) HighAvailabilityConfiguration.create(this.getClass(), this.getProtocolName()); 

Что вы хотите класс T. Есть способы получить это, но мне нужна подпись метода для HighAvailabilityConfiguration.create (...). Это аргумент типа или аргумент класса?

Кстати, мне не нравится защищенная переменная - намного хуже, чем литой IMO.