装璜器模式
定义
装璜器模式也叫包装模式
- 在不扭转原有对象的根底上,把性能附加到对象上,提供了比继承更有弹性的代替计划
- 可能扩大原有对象的性能
属于结构型模式
生存中的例子
买煎饼
- 咱们煎饼能够加鸡蛋,加香肠
蛋糕
- 能够加豆沙加各种各样的货色
通用构造
个别都是在构造方法当中来传入对应须要包装的对象
Component
- 是一个接口或者是抽象类,就是定义咱们最外围的对象,也就是最原始的对象。
ConcreteComponent 具体构件
- ConcreteComponent是最外围、最原始、最根本的接口或抽象类的实现,你要装璜的就是它。
Decorator装璜角色
个别是一个抽象类,做什么用呢?
- 实现接口或者形象办法,它外面 可不肯定有形象的办法呀,在它的属性里必然有一个private变量指向 Component形象构件。
具体装璜角色
- ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装璜类,要把你最外围的、最原始的、最根本的货色装璜成其余货色。
案例
煎饼
煎饼须要加香肠,鸡蛋,等
public class SauageDecorator extends BattercakeDecorator{ public SauageDecorator(Battercake battercake) { super(battercake); } protected String getMsg(){ return super.getMsg() + "1根香肠";} public int getPrice(){ return super.getPrice() + 2;}}
public class Test { public static void main(String[] args) { Battercake battercake; battercake = new BaseBattercake(); battercake = new EggDecorator(battercake); battercake = new EggDecorator(battercake); battercake = new SauageDecorator(battercake); System.out.println(battercake.getMsg() + ",总价" + battercake.getPrice()); }}
能够利用装璜器模式疾速的去抉择须要减少的货色
包装日志
public class JsonLogger extends LoggerDecorator { public JsonLogger(Logger logger) { super(logger); } @Override public void info(String s) { JSONObject result = newJsonObject(); result.put("message",s); logger.info(result.toString()); } @Override public void error(String s) { JSONObject result = newJsonObject(); result.put("message",s); logger.info(result.toString()); } public void error(Exception e){ JSONObject result = newJsonObject(); result.put("exception",e.getClass().getName()); String trace = Arrays.toString(e.getStackTrace()); result.put("starckTrace",trace); logger.info(result.toString()); } private JSONObject newJsonObject(){ return new JSONObject(); }}
public class JsonLoggerFactory { public static JsonLogger getLogger(Class clazz){ Logger logger = LoggerFactory.getLogger(clazz); return new JsonLogger(logger); }}
- 咱们能够间接对Loggerfactory的日志包装一层依照本人指定的格局来输入
源码中常见的装璜器
InputStream
BufferedInputStream
public BufferedInputStream(InputStream in) { this(in, DEFAULT_BUFFER_SIZE);}
咱们能够给流包装一层就能够间接在缓冲区去操作了,速度快很多
Spring中的Cache
public TransactionAwareCacheDecorator(Cache targetCache) { Assert.notNull(targetCache, "Target Cache must not be null"); this.targetCache = targetCache; }
能够对缓存包装一层
能够在事物状况下放弃缓存的一致性
Dubbo中的Wrapper
ProtocolFilterWrapper
org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
public ProtocolFilterWrapper(Protocol protocol) { if (protocol == null) { throw new IllegalArgumentException("protocol == null"); } this.protocol = protocol;}
QosProtocolWrapper
org.apache.dubbo.qos.protocol.QosProtocolWrapper
public QosProtocolWrapper(Protocol protocol) { if (protocol == null) { throw new IllegalArgumentException("protocol == null"); } this.protocol = protocol;}
Mybatis中的Cache
public class LruCache implements Cache { private final Cache delegate; private Map<Object, Object> keyMap; private Object eldestKey; public LruCache(Cache delegate) { this.delegate = delegate; setSize(1024); } public void putObject(Object key, Object value) { delegate.putObject(key, value); cycleKeyList(key); } private void cycleKeyList(Object key) { keyMap.put(key, key); if (eldestKey != null) { delegate.removeObject(eldestKey); eldestKey = null; } } public void setSize(final int size) { keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) { private static final long serialVersionUID = 4267176411845948333L; @Override protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) { boolean tooBig = size() > size; if (tooBig) { eldestKey = eldest.getKey(); } return tooBig; } }; }}
在退出元素的四周包装了一层
能够看到每次退出元素的时候都会去比拟元素数量,如果超过了最大的元素数量就会删除第一个节点
装璜器模式和代理模式比照
- 是一种非凡的代理模式
- 强调本身性能扩大,通明的扩大,可动静定制的扩大
- 代理模式强调代理过程的管制
优缺点
长处
是继承的补充,比继承灵便
- 不扭转原有对象的状况下,能疾速扩大性能
- 能够通过不同装璜器类和装璜器类的排列组合实现不同成果
毛病
- 会呈现更多的代码,更多的类
- 嵌套调用代码变得复杂了
问题
认真比照一下装璜者模式和代理模式结构图,想一想你怎么辨别它们,从这里给你什么启发。
- 装璜器次要强调的是本人,扩大的是本人的能力,并且是对继承的扩大
- 代理模式则是为了实现对象的管制,提供一个代理对象进去,通过代理对象来管制原有对象的援用
- 装璜模式是为装璜的对象加强性能;而代理模式对代理的对象施加管制,然而并不象自身的性能进行加强;
剖析一下java IO代码new BufferedReader(new FileReader(""))
为什么能够层层包装,画出类图或从代码层面形容怎么实现的
能够看到在BufferedReader构造方法中能够传入Reader那么在调用的时候就会给其包装一层
private void fill() throws IOException { //这一段都是包装一层走的Buffer int dst; if (markedChar <= UNMARKED) { /* No mark */ dst = 0; } else { /* Marked */ int delta = nextChar - markedChar; if (delta >= readAheadLimit) { /* Gone past read-ahead limit: Invalidate mark */ markedChar = INVALIDATED; readAheadLimit = 0; dst = 0; } else { if (readAheadLimit <= cb.length) { /* Shuffle in the current buffer */ System.arraycopy(cb, markedChar, cb, 0, delta); markedChar = 0; dst = delta; } else { /* Reallocate buffer to accommodate read-ahead limit */ char ncb[] = new char[readAheadLimit]; System.arraycopy(cb, markedChar, ncb, 0, delta); cb = ncb; markedChar = 0; dst = delta; } nextChar = nChars = delta; } } int n; do { //FileReader#read n = in.read(cb, dst, cb.length - dst); } while (n == 0); if (n > 0) { nChars = dst + n; nextChar = dst; }}
我的笔记仓库地址gitee 快来给我点个Star吧