4

ジェネリックスの導入により、インスタンス化やキャストを可能な限り実行することには消極的です。しかし、このシナリオではそれを回避する方法がわかりません。

for (CacheableObject<ICacheable> cacheableObject : cacheableObjects) {
    ICacheable iCacheable = cacheableObject.getObject();
    if (iCacheable instanceof MyObject) {
        MyObject myObject = (MyObject) iCacheable;
        myObjects.put(myObject.getKey(), myObject);
    } else if (iCacheable instanceof OtherObject) {
        OtherObject otherObject = (OtherObject) iCacheable;
        otherObjects.put(otherObject.getKey(), otherObject);
    }
}

上記のコードでは、ICacheablesはMyObjectまたはOtherObjectのインスタンスのみである必要があることを知っています。これに応じて、それらを2つの別々のマップに配置し、さらに下の処理を実行します。

私のinstanceofチェックなしでこれを行う別の方法があるかどうか興味があります。

ありがとう

4

3 に答える 3

2

二重呼び出しを使用できます。それがより良い解決策であるという約束はありませんが、代替手段です。

コード例

import java.util.HashMap;

public class Example {

    public static void main(String[] argv) {
        Example ex = new Example();
        ICacheable[] cacheableObjects = new ICacheable[]{new MyObject(), new OtherObject()};

        for (ICacheable iCacheable : cacheableObjects) {
            // depending on whether the object is a MyObject or an OtherObject,
            // the .put(Example) method will double dispatch to either
            // the put(MyObject) or  put(OtherObject) method, below
            iCacheable.put(ex);
        }

        System.out.println("myObjects: "+ex.myObjects.size());
        System.out.println("otherObjects: "+ex.otherObjects.size());
    }

    private HashMap<String, MyObject> myObjects = new HashMap<String, MyObject>();
    private HashMap<String, OtherObject> otherObjects = new HashMap<String, OtherObject>();

    public Example() {

    }

    public void put(MyObject myObject) {
        myObjects.put(myObject.getKey(), myObject);
    }

    public void put(OtherObject otherObject) {
        otherObjects.put(otherObject.getKey(), otherObject);
    }

}

interface ICacheable {
    public String getKey();
    public void put(Example ex);
}

class MyObject implements ICacheable {

    public String getKey() {
        return "MyObject"+this.hashCode();
    }

    public void put(Example ex) {
        ex.put(this);
    }
}

class OtherObject implements ICacheable {

    public String getKey() {
       return "OtherObject"+this.hashCode();
    }

    public void put(Example ex) {
        ex.put(this);
    }

}

ここでの考え方は、キャストや使用の代わりに、オブジェクトのオーバーロードされたメソッドに自分自身を渡すオブジェクトのメソッドをinstanceof呼び出すということです。どのメソッドが呼び出されるかは、そのオブジェクトのタイプによって異なります。iCacheable.put(...)Example

Visitor パターンも参照してください。私のコード例は、ICacheable.put(...)メソッドがまとまりがないためににおいがしますが、Visitor パターンで定義されたインターフェイスを使用すると、そのにおいを取り除くことができます。

クラスthis.put(iCacheable)から電話できないのはなぜですか?Example

Java では、オーバーライドは常に実行時にバインドされますが、オーバーロードはもう少し複雑です。動的ディスパッチとは、メソッドの実装が実行時に選択されることを意味しますが、メソッドのシグネチャはコンパイル時に決定されます。(詳細については、Java 言語仕様の第 8.4.9 章を参照してください。また、本のJava Puzzlersの 137 ページにあるパズル「Making a Hash of It」も参照してください。)

于 2012-11-02T23:10:57.420 に答える
1

各マップのキャッシュされたオブジェクトを 1 つのマップに結合する方法はありませんか? それらのキーはそれらを分離しておくことができるので、それらを 1 つのマップに格納できます。それができない場合は、

Map<Class,Map<Key,ICacheable>>

次にこれを行います:

Map<Class,Map<Key,ICacheable>> cache = ...;

public void cache( ICacheable cacheable ) {
   if( cache.containsKey( cacheable.getClass() ) {
      cache.put( cacheable.getClass(), new Map<Key,ICacheable>() );
   }
   cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable );
}
于 2012-11-02T23:28:53.530 に答える
0

次のことができます。

  1. ICachableInterfaceメソッドへの引数として指定された 2 つのマップのいずれかにオブジェクトを配置することを処理するメソッドをインターフェイスに追加します。
  2. このメソッドを 2 つの実装クラスのそれぞれに実装し、各クラスに自分自身を配置する Map を決定させます。
  3. for ループのチェックを削除し、メソッドを手順 1 で定義した新しいメソッドの呼び出しにinstanceof置き換えます。put

ただし、これは良い設計ではありません。このインターフェイスを実装する別のクラスと 3 番目のマップがある場合は、別の Map を新しいメソッドに渡す必要があるからです。

于 2012-11-02T23:12:40.290 に答える