Java - 扩展哈希映射 - 对象与泛型行为

2022-09-03 14:49:48

我正在编写一个简单的基于缓存,其工作原理如下:HashMap

  1. 如果请求在缓存中,则返回其 .keyvalue
  2. 如果请求不存在,请运行基于 生成的方法,存储两者,返回 。keyvaluekeyvalue

代码:

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);
}

它非常简单,效果很好。但是,我讨厌太阳决定将a作为其论据而不是。我已经读了足够多的关于它的文章,知道它背后有一些理由(我不同意,但这是另一个故事)。get()ObjectK

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

一种解决方案是从“是”切换到“有一个”关系,这更好,更干净,但随后无法实现,这有几个原因会很好。代码:HashMapCacheMap

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);
}

任何人都可以想出任何其他(甚至是黑客)解决方案,以便我可以保持成为一个并且仍然在和方面保持类型安全?CacheMapget(Object key)put(K key, V val)

我唯一能想到的就是制作另一个命名为即 这将委派给 ,但我不能强迫任何人使用新方法而不是通常的方法。getValue(Key k)get(Object key)


答案 1

不。您已经找到了切换到“有-a”关系的正确解决方案。(坦率地说,如果该方法尚不存在,则让该方法计算新值是令人惊讶的,违反了契约,并且可能导致许多其他方法的极其奇怪的行为。这是番石榴离开的原因的很大一部分,它提供了几乎这种确切的行为 - 因为它充满了问题。getMapMapMaker

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


答案 2

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


推荐