4

外部ライブラリとその API とのインターフェイスを処理するフレームワークを作成しようとしています。その一環として、多くの (70 程度の) 考えられるメッセージ クラスのそれぞれに同じ名前と型を持つヘッダー フィールドを設定する必要があります。残念ながら、ヘッダー フィールドを含む共通の基本クラスから各メッセージ クラスを派生させるのではなく、それぞれが完全に分離されています。

おもちゃの例として:

public class A
{
   public Header header;
   public Integer aData;
}

public class B
{
   public Header header;
   public Long bData;
}

A と B がヘッダーを含む基本クラスから派生した場所で、彼らが適切に設計した場合、次のようにすることができます。

public boolean sendMessage(BaseType b)
{
   b.header = populateHeader();
   stuffNecessaryToSendMessage();
}

しかし現状では、Object が唯一の共通クラスです。私が考えたさまざまなオプションは次のとおりです。

  • 種類ごとに別の方法。これは機能し、高速ですが、コードの重複は憂鬱なほど無駄になります。
  • 各型をサブクラス化し、共通のインターフェイスを実装させることができます。これは機能しますが、70 以上のサブクラスを作成し、元のメッセージング クラスの代わりにそれらを使用するようにコードを変更することは、橋渡しが行き過ぎています。
  • 反射。実行可能ですが、遅すぎると思います(ここではパフォーマンスが問題です)

これらを考えると、それぞれに個別の方法が最善の策のように思えますが、より良いオプションが欲しいです.

4

3 に答える 3

2

以下をお勧めします。必要なインターフェイスのセットを作成します。例えば

public interface HeaderHolder {
    public void setHeader(Header header);
    public Header getHeader();
}

あなたのクラスにそれらを実装してもらいたいです。つまり、あなたのクラスBは次のように定義されているようです

class B implements HeaderHolder {...}

残念ながらそうではありません。今問題!

ファサードを作成する:

public class InterfaceWrapper {
    public <T> T wrap(Object obj, Class<T> api) {...}
}

この段階で、動的プロキシを使用して実装できます。はい、動的プロキシはリフレクションを使用しますが、今は忘れてください。

完了したらInterfaceWrapper、次のように使用できます。

B b = new B();
new IntefaceWrapper().wrap(b, HeaderHolder.class).setHeader("my header");

ご覧のとおり、必要なクラスにヘッダーを設定できます (適切なプロパティがある場合)。完了したら、パフォーマンスを確認できます。動的プロキシでのリフレクションの使用がボトルネックである場合にのみ、実装をコード生成に変更します (たとえば、カスタム アノテーション、パッケージ名などに基づく)。これを行うのに役立つツールがたくさんあります。または、そのようなロジックを自分で実装することもできます。IntefaceWrapperポイントは、他のコードを変更することなく、いつでも実装を変更できるということです。

ただし、時期尚早の最適化は避けてください。最近、リフレクションは非常に効率的に機能します。Sun/Oracle はこれを達成するために懸命に働きました。たとえば、オンザフライでクラスを作成し、それらをキャッシュしてリフレクションを高速化します。したがって、おそらく完全なフローを考慮に入れると、リフレクティブ コールにはあま​​り時間がかかりません。

于 2013-05-16T17:36:28.870 に答える
1

私が知っている唯一のライブラリは、このDozerを実行できます。リフレクションを使用しますが、良いニュースは、独自のリフレクション コードを記述して遅いことを発見するよりも、遅いかどうかをテストする方が簡単だということです。

デフォルトでは、dozer は 2 つのオブジェクトが完全に異なっていても、同じ getter/setter を呼び出します。ただし、はるかに複雑な方法で構成できます。たとえば、フィールドに直接アクセスするように指示することもできます。Map を List に変換するカスタム コンバーターを指定できます。

移入されたインスタンスを 1 つだけ、または自分のインスタンスを使用して、次のようBaseTypeに言うことができます。dozer.map(baseType, SubType.class);

于 2013-05-16T17:28:26.980 に答える
1

プロジェクトのビルド時にこれらの 70 以上のサブクラスを動的に生成するのはどうですか? そうすれば、70 以上のソース ファイルを維持する必要がなくなり、2 番目の箇条書きのアプローチの利点を維持できます。

于 2013-05-16T17:34:59.143 に答える