通常在開發生產中,對於新需求的實現,咱們通常會有兩種方式來處理,一種是直接修改已有組件的代碼,另外一種是使用繼承方式。第一種顯然會破壞已有組件的穩定性。第二種,會致使大量子類的出現。裝飾器模式能夠動態的爲對象添加功能,它是基於組合的方式來實現該功能的。組合優於繼承。java
裝飾器模式也是須要一個原始需求抽象類或者接口,由它的子類或者實現類來完成它的實際功能,這是正常需求。當咱們須要作擴展需求的時候,須要一個裝飾抽象類(注意這裏只有抽象類,沒有接口)來繼承該原始需求抽象類或者接口,目的是爲了定義委託對象。再由該裝飾抽象類的子類來完成擴展的需求。具體實例能夠參考 設計模式整理 apache
在mybatis的緩存模塊中,它使用了裝飾器模式的變體,將裝飾抽象類直接放到了裝飾實現類的內部,爲了作一個比較,咱們來看一下它的原始需求接口,基本實現類和它的裝飾實現類設計模式
package org.apache.ibatis.cache; import java.util.concurrent.locks.ReadWriteLock; //原始需求接口 public interface Cache { //該緩存對象的id String getId(); //向緩存中添加數據,通常狀況下,key是CacheKey,value是查詢結果 void putObject(Object var1, Object var2); //根據指定的key,在緩存中查找對應的結果對象 Object getObject(Object var1); //刪除key對應的緩存項 Object removeObject(Object var1); //清空緩存 void clear(); //緩存項的個數 int getSize(); //獲取讀寫鎖 ReadWriteLock getReadWriteLock(); }
基本實現類PerpetualCache,咱們能夠看到它就是對一個HashMap的操做,實現了緩存的基本功能。緩存
package org.apache.ibatis.cache.impl; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import org.apache.ibatis.cache.Cache; import org.apache.ibatis.cache.CacheException; public class PerpetualCache implements Cache { //Cache對象的惟一標識 private final String id; //用以記錄緩存項的Map對象 private Map<Object, Object> cache = new HashMap(); public PerpetualCache(String id) { this.id = id; } public String getId() { return this.id; } public int getSize() { return this.cache.size(); } public void putObject(Object key, Object value) { this.cache.put(key, value); } public Object getObject(Object key) { return this.cache.get(key); } public Object removeObject(Object key) { return this.cache.remove(key); } public void clear() { this.cache.clear(); } public ReadWriteLock getReadWriteLock() { return null; } public boolean equals(Object o) { if(this.getId() == null) { throw new CacheException("Cache instances require an ID."); } else if(this == o) { return true; } else if(!(o instanceof Cache)) { return false; } else { Cache otherCache = (Cache)o; return this.getId().equals(otherCache.getId()); } } public int hashCode() { if(this.getId() == null) { throw new CacheException("Cache instances require an ID."); } else { return this.getId().hashCode(); } } }
它的裝飾器實現類(以BlockingCache爲例,實際上它有不少的裝飾器實現類)mybatis
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.apache.ibatis.cache.decorators; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import org.apache.ibatis.cache.Cache; import org.apache.ibatis.cache.CacheException; //阻塞版本的緩存裝飾器 public class BlockingCache implements Cache { //阻塞超時時長 private long timeout; //全部的裝飾器實現類所共有的底層緩存,所表明着裝飾抽象類,雖然這裏不是一個抽象類,而是一個接口 //至關於在裝飾抽象類中使用委託機制是一個道理,這裏委託的也是基本緩存實現類PerpetualCache private final Cache delegate; //每一個key都有所對應的重入鎖ReetrantLock對象 private final ConcurrentHashMap<Object, ReentrantLock> locks; public BlockingCache(Cache delegate) { this.delegate = delegate; this.locks = new ConcurrentHashMap(); } public String getId() { return this.delegate.getId(); } public int getSize() { return this.delegate.getSize(); } //此處進行了重入鎖的釋放,對委託類進行調用外,進行了加強 public void putObject(Object key, Object value) { try { this.delegate.putObject(key, value); } finally { this.releaseLock(key); } } //此處進行了鎖操做和釋放,具體能夠看到後面的實現 public Object getObject(Object key) { this.acquireLock(key); Object value = this.delegate.getObject(key); if(value != null) { this.releaseLock(key); } return value; } public Object removeObject(Object key) { this.releaseLock(key); return null; } public void clear() { this.delegate.clear(); } public ReadWriteLock getReadWriteLock() { return null; } //由key來獲得鎖 private ReentrantLock getLockForKey(Object key) { //重入鎖對象 ReentrantLock lock = new ReentrantLock(); //若是locks(ConcurrentHashMap)中存在key,則趕回value,若是不存在則將key,value寫入locks中,並返回null ReentrantLock previous = (ReentrantLock)this.locks.putIfAbsent(key, lock); //若是key拿不到鎖,則使用新的lock,若是能拿到則使用拿到的value return previous == null?lock:previous; } //得到鎖 private void acquireLock(Object key) { //拿到重入鎖 Lock lock = this.getLockForKey(key); //若是該鎖是帶超時時間的 if(this.timeout > 0L) { try { //在timeout時長後去拿取鎖(注意這裏不是鎖多長時間),拿到返回true,拿不到返回false boolean acquired = lock.tryLock(this.timeout, TimeUnit.MILLISECONDS); //拿不到鎖,拋出異常 if(!acquired) { throw new CacheException("Couldn't get a lock in " + this.timeout + " for the key " + key + " at the cache " + this.delegate.getId()); } } catch (InterruptedException var4) { throw new CacheException("Got interrupted while trying to acquire lock for key " + key, var4); } //若是該鎖不帶超時時間 } else { //直接鎖定 lock.lock(); } } //釋放鎖 private void releaseLock(Object key) { //拿取鎖 ReentrantLock lock = (ReentrantLock)this.locks.get(key); //判斷拿到的鎖是不是當前線程持有的 if(lock.isHeldByCurrentThread()) { //釋放鎖 lock.unlock(); } } public long getTimeout() { return this.timeout; } public void setTimeout(long timeout) { this.timeout = timeout; } }