通常在开发生产中,对于新需求的实现,咱们通常会有两种方式来处理,一种是直接修改已有组件的代码,另外一种是使用继承方式。第一种显然会破坏已有组件的稳定性。第二种,会致使大量子类的出现。装饰器模式能够动态的为对象添加功能,它是基于组合的方式来实现该功能的。组合优于继承。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; } }