15

我正在编写一个HashMap基于简单的 Cache ,其工作方式如下:

  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()将 aObject作为其论点而不是K. 我已经阅读了足够多的内容,知道它背后有一些基本原理(我不同意,但这是另一个故事)。

我的问题出在注释行中,因为似乎必须取消选中演员。由于类型擦除,我无法检查是否key是类型K(正确put()功能所必需的),因此该方法容易出错。

一种解决方案是从“is a”切换到“has a”HashMap关系,这种关系更好更干净,但由于多种原因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);
}

任何人都可以提出任何其他(甚至是骇人听闻的)解决方案,以便我可以在 and 方面保持Cache一个并且Map仍然是类型安全的吗?get(Object key)put(K key, V val)

我唯一能想到的就是创建另一个名为 ie 的方法getValue(Key k),该方法将委托给get(Object key),但是我不能强迫任何人使用新方法而不是通常的方法。

4

2 回答 2

15

没有。您已经找到了切换到“拥有”关系的正确解决方案。(坦率地说,get如果一个新值不存在,让该方法计算一个新值是令人惊讶的,违反了Map合同,并且可能导致许多其他方法的极其奇怪的行为。这是 Guava 离开的重要部分MapMaker,它提供了几乎这种精确的行为——因为它充满了问题。)

也就是说,例如 GuavaCache所做的是它公开了一个Map<K, V> asMap() 视图,这是您可以做的事情。这为您提供了 a 的大部分优点,Map而不会影响类型安全。

于 2012-04-27T16:12:10.577 回答
0

毫无疑问,has-a 关系是正确的实现。应该从缓存类中删除如何生成值的业务逻辑。

于 2012-04-27T16:24:15.093 回答