2012-04-27 62 views
15

我正在寫一個簡單的基於HashMap緩存的工作原理如下:爪哇 - 擴展的HashMap - 對象對仿製藥的行爲

  1. 如果請求key在高速緩存,返回其value
  2. 如果請求key有,運行基於key產生value的方法,同時存儲,返回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); 
} 

這是非常簡單和行之有效的。然而,我討厭太陽的get()決定採取Object作爲其論點,而不是K。我已經讀了足夠多的信息,知道它背後有一些基本原理(我不同意,但那是另一回事)。

我的問題是在註釋行中,因爲它看起來像已經被取消選中。由於類型刪除,我無法檢查key是否爲K(正確需要put()功能),因此該方法容易出錯。

一個解決辦法是從開關「是一個」到「有」 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); 
} 

任何人都可以拿出任何其他(甚至hackish的)解決方案,這樣我可以保持Cache是一個Map,仍然是類型的get(Object key)put(K key, V val)條款安全嗎?

我唯一能想到的就是製作另一個名爲getValue(Key k)的方法,它將委託給get(Object key),但我不能強迫任何人使用新方法而不是通常的方法。

+1

你可以實現'getA'或'myget'你不能改變Map的行爲。get()儘可能不能強制直接使用接口而不是類直接重新編譯的代碼。 – 2012-04-27 16:14:07

回答

15

沒有。您找到了切換到「一對一」關係的正確解決方案。 (坦率地說,讓get方法計算出一個新值,如果還不存在的話是令人驚訝的,違反Map合同,並且會導致其他許多方法出現極其奇怪的行爲,這是Guava搬走的重要原因從MapMaker,提供幾乎這種確切的行爲 - 因爲它只是這樣riddled有問題。)

這就是說,例如番石榴的Cache確實暴露了Map<K, V> asMap()查看,這是你可以做的事情。這樣可以在不影響型號安全的情況下爲您提供Map的大部分優點。

+0

看來'MapMaker'確實做了我所做的:)。 我部分意識到奇怪的行爲。 'V getData(K key)'方法是'abstract',因此只能在Cache實例化中指定(實現)。我甚至試圖讓「最終抽象」類(儘管我知道100%它不起作用)或者只是「最終」(用匿名內部類重寫的方法 - 當然也不行)以確保沒有人會試圖用一些業務邏輯來將這段危險的代碼分類。 無論如何,非常感謝,與'asMap()'有一個_view_的「has-a」關係。 – 2012-04-27 16:38:17

+0

順便說一句,我不能相信我錯過了番石榴的緩存。我現在不會使用它(當我有自己的實現時),但如果我知道昨天...... :) – 2012-04-27 16:55:31

+5

你......應該考慮使用番石榴的「Cache」。它用於Google生產,所以它經過了嚴格的測試和優化,並且它有很多便利功能[http://code.google.com/p/guava-libraries/wiki/CachesExplained]。 – 2012-04-27 16:59:47

0

明確地說,一個關係是一個正確的實現。如何生成值的業務邏輯應該從緩存類中移除。

+0

這是有趣的部分 - 沒有邏輯!該方法是'abstract',因此應該只在Cache實例化中指定(實現,覆蓋 - 無論你最喜歡哪一個)。我甚至試圖讓「最終抽象」類(儘管我知道100%它不起作用)或者只是「最終」(用匿名內部類重寫的方法 - 當然也不行)以確保沒有人會試圖用一些業務邏輯來將這段危險的代碼分類。 – 2012-04-27 16:36:53