15

私は次のように機能する単純なHashMapベースのキャッシュを書いています:

  1. 要求されたものがキャッシュにある場合はkey そのを返しますvalue
  2. 要求されたkey ものがないvalue場合は、に基づいて生成しkey、両方を格納し、を返すメソッドを実行しvalueます。

コード:

import java.util.HashMap;

abstract class Cache<K, V> extends HashMap<K, V> {  
    @Override
    public V get(Object key) {
        if (containsKey(key)) {
            return super.get(key);
        } else {
            V val = getData(key);
            put((K)key, val);    // this is the line I'm discussing below
            return val;
        }
    }

    public abstract V getData(Object key);
}

それはかなり簡単で、うまく機能します。しかし、私は、引数としてではなく、を採用するというSunの決定を嫌います。私はそれについて十分に読んだので、その背後にいくつかの論理的根拠があることを知っています(私は同意しませんが、それは別の話です)。get()ObjectK

キャストのチェックを外す必要があるように見えるので、私の問題はコメント行にあります。型消去のためkey、型K(適切なput()機能に必要)であるかどうかを確認する方法がありません。したがって、メソッドはエラーが発生しやすくなります。

1つの解決策は、「is a」から「HashMaphasa」の関係に切り替えることです。これは、はるかに優れたクリーンな関係ですが、いくつかの理由でこれをCache実装できません。Mapコード:

import java.util.HashMap;
import java.util.Map;

abstract class Cache<K, V> {
    private final Map<K, V> map = new HashMap<K, V>();

    public V get(K key) {
        if (map.containsKey(key)) {
            return map.get(key);
        } else {
            V val = getData(key);
            map.put(key, val);
            return val;
        }
    }

    public abstract V getData(K key);
}

誰かが他の(ハックっぽい)解決策を思い付くことができますか?そうすれば、私はとの点で安全であり続けるCacheことができますか?Mapget(Object key)put(K key, V val)

getValue(Key k)私が考えることができる唯一のことは、に委任するという名前の別のメソッドを作成することget(Object key)ですが、通常のメソッドの代わりに新しいメソッドを使用するように強制することはできません。

4

2 に答える 2

15

いいえ。「has-a」関係に切り替えることで、適切な解決策を見つけました。(率直に言って、getメソッドがまだ存在しない場合に新しい値を計算させることは驚くべきことであり、契約に違反し、他の多くのメソッドで非常に奇妙な動作につながる可能性があります。これは、MapGuava が から離れた理由の大きな部分でした。MapMakerこれは、ほぼこの正確な動作を提供しました-それは問題だらけだったからです.)

そうは言っても、たとえばGuava'sが行うことは、ビューCacheを公開することです。これはあなたができることです。これにより、型の安全性を損なうことなく、 a のほとんどの利点が得られます。Map<K, V> asMap() Map

于 2012-04-27T16:12:10.577 に答える
0

間違いなく has-a 関係は正しい実装です。値の生成方法に関するビジネス ロジックは、キャッシュ クラスから削除する必要があります。

于 2012-04-27T16:24:15.093 に答える