2010-12-07 62 views
4

所以......自從我離開Uni後,一直躲在爪哇之後,它一直衝到我身上。我試圖重構一些代碼,並且已經將大部分方法都轉移到了我想要的地方。不幸的是,我留下了一個狡猾的代碼。在這一點上,我不得不拋棄一個子類,但我相信應該有更好的方法。如果有人能以更好的方式提供幫助,我會很感激。瞭解Java泛型 - 這可以做得更好嗎?

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,它接受類類型來生成最基本的配置項。我不控制工廠或配置類。他們是我正在使用的圖書館的一部分。但是在所有協議中打開一個協議是很常見的,除了需要設置每個子類的配置上的一些自定義屬性。

編輯:

僅供參考,我會爲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,但這是不允許的。 – 2010-12-07 06:57:27

+0

無論如何,我已經在派生構造函數中創建了類。我試圖消除這種情況,但那不是一個問題,然後狡猾的鑄造。我也試圖通過提供'遞歸泛型'參數(而不是真實名稱)來獲得對基類中子類的引用。簡而言之,如果我不想過度複雜的話,這完美地工作。 – 2010-12-07 07:02:20

1

一個可能的問題 - 是否有任何特殊原因採用Genericised參考「configClass」?它可以只是一個ProtocolConfiguration參考。

此外,由於你提到的setClientName操作只在InteractionProtocolConfig子類中可用我看啊,你做了什麼,是落實邏輯的正確道路。然而,可能做的優化是具有InteractionProtocolConfig類型的子類級別實例變量。之後,您可以始終使用該引用,而不必在任何想要在子類中使用的位置下載配置變量。

但是,如果方法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(...)的方法簽名。那是一個Type參數還是一個Class參數?順便說一下,我不喜歡那裏的保護變量 - 比鑄造IMO差很多。