Identity Map

Situace

Trvalé úložiště dat obsahuje entity, jejichž obrazy se vytváří v aplikaci. Tyto entity jsou rozlišeny klíčem. Pod trvalým úložištěm si lze představit například databázi, pod entitami zákazníky a pod klíčem jejich ID. Problém

Nic nebrání tomu, aby aplikace volně vytvářela instance entit a ty rozesílala do různých částí programu. Případná změna jedné takové instance se neprojeví v ostatních instancích a dojde k porušení principu SSOT. Také je nutné při každém požadavku na entitu načítat aktuální data z trvalého úložiště, což je zbytečné, pokud se uložená instance mezitím nezměnila.

kód v jazyce Java - Zobrazit

  1. public Customer getCustomer(long id)
  2. {
  3.   // ...
  4.   // načíst data z databáze
  5.   // SELECT * FROM customer WHERE id = ?
  6.   // ...
  7.  
  8.   Customer entity = new Customer();
  9.   // ...
  10.   entity.setName(result.getString("name"));
  11.   entity.setSurname(result.getString("surname"));
  12.   // ...
  13.   return entity;
  14. }
  15.  
  16. public void problem()
  17. {
  18.   Customer c1 = getCustomer(1);
  19.   Customer c2 = getCustomer(1);
  20.  
  21.   c1.setName("John");
  22.  
  23.   // problém: která instance je teď ta správná
  24.   // instance c1 má ještě staré jméno
  25.   // instance c2 obsahuje již nové jméno
  26. }

Řešení

Řešení tohoto problému spočívá v odstínění programu od vytváření instancí. Vznikne nová třída, která bude instance entit spravovat a vytvářet je pouze tehdy, když instance entity s požadovaným klíčem neexistuje. V podstatě se jedná o prostou vyrovnávací paměť.

Varianty

  • implicitní – jedna mapa pro každý typ entity
  • explicitní – pouze jedna univerzální mapa, typ entity se specifikuje později

Implementace

kód v jazyce Java - Zobrazit

  1. import java.util.HashMap;
  2. import java.util.Map;
  3.  
  4. /**
  5.  * Identity Map.
  6.  *
  7.  * @author Vojtěch Hordějčuk
  8.  * @param <K>
  9.  * třída klíče (např. Long)
  10.  * @param <V>
  11.  * třída entity (např. Customer)
  12.  */
  13. public class IdentityMap<K, V>
  14. {
  15.   /**
  16.    * cache obsahující jedinečné instance entit
  17.    */
  18.   private final Map<K, V> cache;
  19.   /**
  20.    * DAO pro načítání entit z trvalého úložiště
  21.    */
  22.   private final DAO<V> dao;
  23.  
  24.   /**
  25.    * Vytvoří novou instanci.
  26.    *
  27.    * @param dao
  28.    * DAO pro zadaný typ entit
  29.    */
  30.   public IdentityMap(final DAO<V> dao)
  31.   {
  32.     this.cache = new HashMap<K, V>();
  33.     this.dao = dao;
  34.   }
  35.  
  36.   /**
  37.    * Vrátí jedinečnou instanci pro zadaný klíč. Pokud instance neexistuje, bude
  38.    * vytvořena a uložena do cache.
  39.    *
  40.    * @param key
  41.    * klíč
  42.    * @return jedinečná instance pro zadaný klíč
  43.    */
  44.   public V getInstance(final K key)
  45.   {
  46.     if (!this.cache.containsKey(key))
  47.     {
  48.       // hodnota s tímto klíčem není v cache
  49.       // bude vytvořena nová instance
  50.  
  51.       final V fresh = dao.load(key);
  52.       this.cache.put(key, fresh);
  53.       return fresh;
  54.     }
  55.  
  56.     // vrátit již existující hodnotu z cache
  57.  
  58.     return this.cache.get(key);
  59.   }
  60. }

Reference