2010-12-07 2 views
4

................ 유니, 나 떠난 이후 자바 피하는 후, 그것은 내게 밀려왔다. 나는 일부 코드를 리팩토링하려고 시도하고 있으며, 내가 원하는 곳으로가는 길은 대부분 가지고있다. 불행히도, 나는 한 조각의 dodgy 코드가 남아있다. 이 시점에서 하위 클래스로 캐스팅해야하지만 더 나은 방법이 있어야합니다. 누구든지 그 더 나은 방법으로 도울 수 있다면, 나는 그것을 감사 할 것입니다.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를 가지고 있기 때문입니다. 필자는 factory 나 Configuration 클래스를 제어하지 않는다. 그들은 내가 사용하고있는 도서관의 한 부분입니다. 그러나 각 하위 클래스에 대한 구성의 몇 가지 사용자 지정 속성을 설정해야한다는 요구 사항을 제외하면 프로토콜을 여는 것은 모든 프로토콜에서 공통적입니다.

편집 : 참고로

, 나는 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

이것이 현재 내가 시도하고있는 것입니다. 그러나 문제는 create 메소드의 this.getClass()입니다. T.class 일 필요가 있지만 허용되지 않습니다. –

+0

어쨌든 파생 생성자에 클래스 을 이미 만들었습니다. 그걸 없애려고했지만 그게 문제가 된 거지. 나는 또한 '재귀 generics'매개 변수 (실제 이름이 아님)를 제공함으로써 기본 클래스의 하위 클래스에 대한 참조를 얻으려고했다. 짧은 대답은 내가 물건을 지나치게 복잡하게하려고하지 않으면 완벽하게 작동합니다. –

+0

내가 말했듯이 내가 편집기에서 그 코드를 자르지 않았으므로 나는 확인하지 않았다. 나는'this.getClass()'가 InteractionProtocol 클래스를 리턴 할 것이기 때문에이 트릭을 할 것이라고 생각했을 것이다. 대안으로'private class clazz; '변수를 설정하거나 생성자로 전달할 수 있지만이 경우에는'getClass()'가 작동하지 않는다는 것이 이상하게 보입니다. – drekka

1

가능한 질문 - Genericised 참조 "configClass"을 채택한 특별한 이유가 있습니까? 그것은 아주 잘 ProtocolConfiguration 참조 일 수 있습니다.

setClientName 작업은 하위 클래스 InteractionProtocolConfig에서만 사용할 수 있으므로, 논리를 구현하는 올바른 방법은 내가 한 일입니다. 그러나 일 수있는 최적화는 InteractionProtocolConfig 유형의 하위 클래스 수준 인스턴스 변수를 갖는 것입니다. 그런 다음 하위 클래스에서 사용하고자하는 모든 위치에서 구성 변수를 다운 캐스팅하지 않고 항상 해당 참조를 사용할 수 있습니다.

그러나 방법이 preProcessConfig이면 다운 캐스팅하는 유일한 장소 인 경우 전술 한 전략을 채택하는 데 많은 포인트가 없습니다.

+0

나는 configClass 멤버 변수의 "genericising"과 전체 Protocol 클래스를 "타이핑"해야한다는 것에 동의하고 방황합니다. – drozzy

1

현재) this.getClass을 (원하지 않는 :

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

은 당신이 원하는 것은 T의 클래스입니다. 그것을 얻을 수있는 방법이 있지만 HighAvailabilityConfiguration.create (...)에 대한 메서드 서명이 필요합니다. 유형 인수 또는 클래스 인수입니까?

그런데 보호 된 변수가 좋지 않습니다. 캐스트 IMO보다 훨씬 나쁩니다.

+0

당신은 절대적으로 옳았습니다. 데렉의 대답을 편집하여 올바른 전화를 걸도록했습니다. 보호 된 변수는 하위 클래스에 의해 설정 되었기 때문에 거기에있었습니다. 그것은 실제로 내 코드에서 최종입니다. 하위 클래스에서 참조되거나 필요하지는 않지만 private로 변경합니다. 귀하의 의견을 보내 주셔서 감사합니다. –

관련 문제