2010-12-07 9 views
4

私はUniを離れて以来、Javaを悩まして、それは私の上に押しつけられています。私はいくつかのコードをリファクタリングしようとしており、私がしたいところにほとんどの道を持っています。残念ながら、私は1つの厄介なコードが残っています。この時点でサブクラスにキャストする必要がありますが、より良い方法があるはずです。誰かがその良い方法で助けることができれば、私はそれを感謝します。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を持っていて、ほとんどの完全な設定項目を生成するためにクラスタイプを取るからです。私は工場や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; 
    }; 
} 

私はそれを行うと、すべてがシンプルにすべきだと思います。抽象的に拡張された各プロトコルの新しいクラスを作成し、メソッドのジェネリック型にするだけです。

あなたがthis.getClass(したくない
+0

これは私が現在試みていることです。しかし問題は、createメソッドのthis.getClass()です。 T.classである必要がありますが、これは許可されていません。 –

+0

私は既に派生コンストラクタにクラスを作成していました。私もそれを排除しようとしていましたが、それはドッジ・キャスティングの問題ではありません。私はまた、 '再帰ジェネリック'パラメータ(実際の名前ではない)を提供することによって、ベースクラスのサブクラスへの参照を取得しようとしていました。短い答えは、私が物事を過度に複雑化しようとしなければ、これは完全に機能します。 –

+0

私が言ったように私はエディタでそのコードをカットしていないので、私は確認していません。私は 'this.getClass()'がInteractionProtocolクラスを返すので、このトリックを行うと思っていたでしょう。代わりに、 'private Class clazz;という変数を設定することもできますし、コンストラクタとして渡すこともできますが、' getClass() 'はこの場合にはうまくいきません。 – drekka

1

可能性のある質問 - Genericisedリファレンス「configClass」を採用する特別な理由はありますか?それはちょうどProtocolConfigurationの参照であることができます。

setClientName操作はInteractionProtocolConfigサブクラスでのみ利用できると言われていますので、ロジックを実装する正しい方法は何ですか?しかし、のような最適化は、InteractionProtocolConfigのサブクラスレベルインスタンス変数を持つことです。その後、サブクラスで使用したいと思う場所でconfig変数をダウンキャストしなくても、常にその参照を使用することができます。

しかし、方法preProcessConfigがダウンキャストしている唯一の場所である場合、上記の戦略を採用することにはあまり意味がありません。

+0

私は、configClassメンバー変数の「一般化」と、プロトコルクラス全体の「入力」の必要性について同意しています。 – drozzy

1

)ここでは何をしたい

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

はTのクラスです。それを得る方法がありますが、HighAvailabilityConfiguration.create(...)のメソッドシグネチャが必要です。それは型引数かクラス引数ですか?

ところで、私はそこに保護された変数が好きではありません - キャストIMOよりずっと悪いです。

+0

あなたは正しいです、作成するための正しい呼び出しを含むDerekの答えを編集しました。保護された変数は、サブクラスによって設定されていたためにそこにありました。実際には私のコードでは最終的です。サブクラスでは参照または必須ではありませんが、私はそれをprivateに変更します。あなたのご意見ありがとうございます。 –

関連する問題