3

1 つの引数を持つメソッドがあり、引数のタイプに応じて、メソッドが異なることを行うとします。

メソッドを呼び出しましょうdoMethod():

private int doMethod(Class1 x) {
    // do something with x
}

private int doMethod(Class2 x) {
   // do someting else with x
}

...

私はこれらの方法をいくつか持っています。ここで問題が発生します。上記の他のすべてのクラスのスーパークラスである引数を取る別のメソッドがあります(ただし、実際には常にそのサブクラスの1つです):

private void otherMethod(SuperClass obj) {
      // I do something clever with obj, 
      // which is the super class of Class1, Class2, .. Classn
      // however this method is always called with either Class1, Class2, etc.
      // never with an instance of SuperClass itself.

      // finally I want to execute doMethod() on obj:
      int result = doMethod(obj);        

      // fails because doMethod(SuperClass) does not exist
}

最後に、 を作成しdoMethod(Superclass obj)、 obj をチェックしてから、キャストinstanceofを呼び出します。doMethod()

これを行うためのより良い方法があるに違いありませんか?現時点では思いつかないので、誰かが私を助けてくれるかもしれません:)

どうもありがとう!

4

1 に答える 1

2

いくつかの可能性:

サブクラス + 訪問者パターン

最終ではないにしても、サブクラスごとにサブクラスを作成できます。メソッドを提供し、Visitor パターンを使用しvisit()て追加の操作を実装できます。doMethod()これにより、後でさまざまな操作を追加する可能性が開かれます。Visitor パターンが正しく行われていれば、操作を新しいサブクラスに追加するのを忘れることはありません (コンパイルされないため)。これは、ニーズに応じて、良い場合とそうでない場合があります。

サブサブクラスは、私が気に入らないこのソリューションの一部です。ここには、クラス階層と複雑さが爆発する危険があります。可能であれば、追加する追加のサブクラスを最終的なものにします。また、拡張しているクラスのいずれかが将来 final になるという問題も発生します (下位互換性が失われますが、不可能ではありません)。

例: http://www.javacodegeeks.com/2013/08/visitor-design-pattern-in-java-example-tutorial.htmlvisit() (この例では、開発者は基本クラスにアクセスし、そこにメソッドを追加します。一方、追加のサブクラスによって実装される共通のインターフェースに追加する必要があります)。

集計 + 訪問者パターン

上記の変形は、独自のクラスが (サブクラスではなく) 他の階層からのクラスのインスタンスを含む並列クラス階層を作成することです。visit()独自のクラス階層 (および必要なその他のメソッド) に追加し、基になる型にアクセスする手段も提供します。これをジェネリックでうまくまとめることができるはずです。

繰り返しになりますが、ここには潜在的に多くの複雑性があります。

「ハンドラー」のマップ

インスタンスのタイプによってキー付けされたマップ内のインターフェイスの実装として操作を検索できます。

// Java-y pseudo-code...
Map<Class<? extends SuperClass>,Function<V,R>> doMethods = new HashMap<>();
doMethods.add(FooClass.class, FooDoMethod.INSTANCE);
doMethods.add(BarClass.class, BarDoMethod.INSTANCE);
...
public R doMethod(V it) {
    Class<? extends V> cls = it.getClass();
    Function<? extends V,R> fn = doMethods.get(cls);
    if(fn==null)
        throw new UnsupportedOperationException(
            "Can't doMethod() on a "+cls.getName());
    return fn.apply(it);
}

ここでのINSTANCEシングルトン オブジェクトはFunction、Java 1.8 (または 1.8 より前の Comparable) の新しいインターフェイスのようなものを実装します。つまり、操作を実装する単一のメソッドを持つインターフェイスの実装です。次に、マップにさらにエントリを追加して、操作がサポートされるタイプを拡張します。サポートされている型ごとに明示的なエントリを追加する必要があります (実際にインスタンスを持つことができる場合は、中間基本クラスであっても、Swing の JComponent と JButton に似ています (どちらも実際のインスタンスとして存在できます)。もちろん、同じ方法で実装する場合は、複数の型に同じ実装を追加します。

次に、マップされたハンドラー (およびマップ自体) へのディスパッチを他のクラスで非表示にすることができます。

(PS申し訳ありませんが、手元にjavacがありません。そうでなければ、これらを適切に試してみました。)

于 2013-11-11T15:42:53.790 に答える