什麼是裝飾者模式設計模式
在不改變原有對象的基礎上附加功能,相比生成子類更靈活。緩存
裝飾者模式應用場景安全
Mybatis緩存,過濾器,網關控制,P2P分控審批app
裝飾者模式定義源碼分析
(1)抽象組件:定義一個抽象接口,來規範準備附加功能的類ui
(2)具體組件:將要被附加功能的類,實現抽象構件角色接口this
(3)抽象裝飾者:持有對具體構件角色的引用並定義與抽象構件角色一致的接口spa
(4)具體裝飾:實現抽象裝飾者角色,負責對具體構件添加額外功能。.net
定義一個接口debug
public interface ComponentCatch { /** * 定義共同行爲的方法標準 */ Object getCatch(String key); void putCatch(String key,Object value); }
定義被裝飾角色
/** * 【一級緩存】,FirstCatch【被裝飾的類】 */ public class FirstCatch implements ComponentCatch { //假裝成一級緩存 HashMap firstCatchMap=new HashMap(); public FirstCatch() { firstCatchMap.put("1","xuyu"); } public Object getCatch(String key) { Object value = firstCatchMap.get(key); System.out.println(">>>>>>>調用一級緩存查詢數據"); return value; } public void putCatch(String key, Object value) { firstCatchMap.put(key,value); } }
定義抽象裝飾角色
/** * 抽象裝飾者:AbstractDecorator,定義【被裝飾者】與【具體裝飾者】共同行爲 */ public abstract class AbstractDecorator implements ComponentCatch { protected ComponentCatch baseCatch; public AbstractDecorator(ComponentCatch baseCatch) { this.baseCatch = baseCatch; } public Object getCatch(String key) { return baseCatch.getCatch(key); } }
定義具體裝飾角色
/** * 二級緩存:SecondCatch,【裝飾者】 * SecondCatch:在不改變原有一級緩存基礎之上搭建二級緩存 */ public class SecondCatch extends AbstractDecorator { //假裝成二級緩存 HashMap secondCatchMap=new HashMap(); public SecondCatch(ComponentCatch baseCatch) { super(baseCatch); } public Object getCatch(String key) { System.out.println(">>>>>>>調用二級緩存查詢數據"); //先查詢二級緩存 Object secondValue = secondCatchMap.get(key); //若是二級緩存沒有,再查詢一級緩存 if(secondValue==null){ Object firstValue = super.getCatch(key); //若是一級緩存有的話 if(firstValue!=null){ //將一級緩存緩存到二級緩存 secondCatchMap.put(key,firstValue); secondValue=firstValue; } } return secondValue; } public void putCatch(String key, Object value) { } }
/** * 三級緩存【裝飾者】 * ThiredCatch:在不改變原有二級緩存的基礎之上搭建三級緩存 */ public class ThiredCatch extends AbstractDecorator { //假裝成三級緩存 HashMap thiredCatchMap=new HashMap(); public ThiredCatch(ComponentCatch baseCatch) { super(baseCatch); } public void putCatch(String key, Object value) { } public Object getCatch(String key) { System.out.println(">>>>>>>調用三級緩存查詢數據"); //先查詢三級緩存 Object thiredValue = thiredCatchMap.get(key); //若是三級緩存沒有,再查詢二級緩存,若是二級緩存爲空的話,再查詢一級緩存 if(thiredValue==null){ Object secondValue = super.getCatch(key); //若是二級緩存不爲空 if(secondValue!=null){ //將二級緩存緩存到三級緩存 thiredCatchMap.put(key,secondValue); thiredValue=secondValue; } } return thiredValue; } }
獲取裝飾類
public class FactoryCatch { public static ComponentCatch getComponentCatch(){ ThiredCatch thiredCatch = new ThiredCatch(new SecondCatch(new FirstCatch())); return thiredCatch; } public static void main(String[] args) { ComponentCatch getComponentCatch=getComponentCatch(); Object value1 = getComponentCatch.getCatch("1"); System.out.println("value1:"+value1); System.out.println("###########################"); Object value2 = getComponentCatch.getCatch("1"); System.out.println("value2:"+value2); } }
輸出結果
>>>>>>>調用三級緩存查詢數據
>>>>>>>調用二級緩存查詢數據
>>>>>>>調用一級緩存查詢數據
value1:xuyu
###########################
>>>>>>>調用三級緩存查詢數據
value2:xuyu
部分源碼
public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) { typeClass = valueOrDefault(typeClass, PerpetualCache.class); evictionClass = valueOrDefault(evictionClass, LruCache.class); Cache cache = new CacheBuilder(currentNamespace) .implementation(typeClass) //添加二級緩存 .addDecorator(evictionClass) .clearInterval(flushInterval) .size(size) .readWrite(readWrite) .blocking(blocking) .properties(props) .build(); configuration.addCache(cache); currentCache = cache; return cache; }
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { //獲取二級緩存 Cache cache = ms.getCache(); //判斷二級緩存是否存在 if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, parameterObject, boundSql); @SuppressWarnings("unchecked") List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
public Object getObject(Object key) { requests++; //這裏獲取二級緩存 final Object value = delegate.getObject(key); if (value != null) { hits++; } if (log.isDebugEnabled()) { log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio()); } return value; }
總結:
裝飾模式和代理模式區別?
代理模式:在方法以前和以後實現處理,在方法上實現加強,隱藏真實方法的真實性,保證安全。
裝飾模式:不改變原有的功能,實現加強,不斷新增不少裝飾。
版權@須臾之餘https://my.oschina.net/u/3995125