1

次のようなシナリオを提示したいと思います。

  • 汎用インターフェースを持っている、
  • さまざまな汎用基本クラスに実装してもらい、
  • 汎用基本クラスのサブクラスを提供し、
  • どういうわけか、サブクラスへの非ジェネリックインターフェイスを取得します。

混乱している?読んで、あなたが解決策についてどう思うか教えてください。

あらゆる種類のキーに基づいて、どこからでも(DB、ファイルなど)、あらゆる種類のオブジェクトを提供するサービスが必要だとします。

良いスタートを切るために、適切なインターフェースを作成しましょう。

public interface ObjectProvider<K, V> {

    V provide(K key);
}

このようにして、あらゆる種類の実装を提供できるようになります。データベースとファイルからオブジェクトを提供したい。

Kに基づくVの提供は、オブジェクトタイプに関係なく、同じDBロジックで実行できると仮定します。したがって、DBアクセス用の汎用基本クラスを記述できます。

public class DBObjectProvider<K, V> implements ObjectProvider<K, V> {

    public V provide(K key) {
        V v = null;
        //some common DB logic to get V based on K
        return v;
    }
}

実際、ファイルからオブジェクトを取得することも、オブジェクトタイプに依存しません。

public class FileObjectProvider<K, V> implements ObjectProvider<K, V> {

    public V provide(K key) {
        V v = null;
        //some common file reading logic to get V based on K
        return v;
    }
}

さて、今では、必要なものを取得するために使用できる2つの汎用クラスがあります。

ここで、これらの一般的な実装の1つを使用して、データベースからStringキーに基づいてStringオブジェクトを取得したいと思います。さらに、SpringXMLを使用してBeanとして定義したいと思います。Spring XMLで汎用Beanを定義する方法はないと思います(私は正しいですか?)ので、代わりに適切なクラスを作成します。私がする必要があるのは:

public class DBStringStringProvider extends DBObjectProvider<String, String>  {
}

今、私はこのBeanを任意の場所に注入できます。

private ObjectProvider<String, String> objectProvider;

すべてが順調です、今重要な部分です。便利なDBString-Stringプロバイダーをさまざまな方法で利用できました(hhmmm ... okではありません)。それからWebサービスを作りたいとしましょう。DBStringStringProviderをCXFWebサービスとして公開し、テストするとします。問題は、そのようなWebサービスのクライアントコードが次のようになることです。

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(<INTERFACE>.class);
<INTERFACE> client = (<INTERFACE>) factory.create();

そのため、DBStringStringProviderの非ジェネリックインターフェイスが必要です。これは、ジェネリック基本クラスを拡張するため、持っていません。

私は次のことができます:

ObjectProvider <String、String>インターフェイスを別のインターフェイスで拡張します。

@WebService
public interface StringStringProvider extends ObjectProvider<String, String> {

    @WebMethod
    String provide(String key);
}

さらに、汎用基本クラスによってすでに実装されている場所に実装します。

public class DBStringStringProvider extends DBObjectProvider<String, String>
implements StringStringProvider {
}

基本クラスですでに導入されているのと同じインターフェースを実装することに少し不快感を覚えます。しかし、このようにして、WSクライアントを利用することができます。

factory.setServiceClass(StringStringProvider.class);
StringStringProvider client = (StringStringProvider) factory.create();

私の質問は:私が今やったことをするのは良い習慣ですか?そうでない場合、他の方法はありますか?

これは、ジェネリックとして定義されているものに対して非ジェネリックインターフェイスを使用するのが最適なシナリオの1つにすぎません。

4

1 に答える 1

1

私は、提起された質問における抽象化のレベルの動機を批判することを嫌います。インターフェイスの一貫性と重複コードの削減のために、これらのシナリオは時々発生します。Java、特に厄介なサービスフレームワークは、このタスクを必要以上に複雑にします。このような不必要な複雑さは、元のデザインが悪いことを意味するものではありません。毎日、Javaは、無意味な冗長性に関連するさまざまな理由で歯を食いしばります。

無償の具体的なサブインターフェイスを定義することが許容可能であり、一般的な方法であることを喜んで確認します。サービスフレームワークの制限を回避しているため、このアクションを実行する必要があります(パラメータ化されたインターフェイスは許可されていません)。

唯一気になるのは、Javaでtypedefを実行しようとしているということです。私がJavaでwrttypedefを実行できた最高の結果は、驚くほど醜い構造になり、複雑さへの嫌悪感から判断して、元の投稿のコメント投稿者が自分の目を測りたくなるでしょう。

実際には問題が発生することはないと思いますが、一般に、この例のような疑似typedefは予期しない痛みを引き起こす可能性があります。T一般的なケースでは、インターフェイスの些細なサブインターフェイスを作成すると、それが適用される 場所の代わりSに使用したくなるでしょう。たとえば、長い間パラメータ化されたJavaクラス式であり、読み取りや入力が面倒で、素晴らしく短い場合があります。ただし、メソッド/サービス呼び出し/コンストラクター引数の場合は、宣言された型として必要です。そうしないと、メソッドまたはクラスの有用性が制限されるリスクがあります。不自然な例:TSSTS

public interface Info extends Map< String, List< FooBar > > {}

public interface Service {
    public Info doSomething( Info info );
}

にAPIを追加しないため、Serviceを受け入れるだけの理由はありません。書かれているように、doSomethingの呼び出し元は、古いマップを入力として受け取ることはできません。Java(他のほぼすべての広く使用されているエンタープライズ言語と同様)は記名的型付けを使用するため、何らかの方法で新しいものを作成し、そのマップのコンテンツで初期化する必要があります。InfoInfoMap< String, List< FooBar > >Info

于 2012-06-23T04:00:05.173 に答える