关于spring:设计模式装饰器模式

4次阅读

共计 4438 个字符,预计需要花费 12 分钟才能阅读完成。

装璜器模式

定义

装璜器模式也叫包装模式

  • 在不扭转原有对象的根底上,把性能附加到对象上,提供了比继承更有弹性的代替计划
  • 可能扩大原有对象的性能

属于结构型模式

生存中的例子

  • 买煎饼

    • 咱们煎饼能够加鸡蛋,加香肠
  • 蛋糕

    • 能够加豆沙加各种各样的货色

通用构造

个别都是在构造方法当中来传入对应须要包装的对象

  • 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;
      }
    };
  }
}

在退出元素的四周包装了一层

能够看到每次退出元素的时候都会去比拟元素数量,如果超过了最大的元素数量就会删除第一个节点

装璜器模式和代理模式比照

  1. 是一种非凡的代理模式
  2. 强调本身性能扩大,通明的扩大,可动静定制的扩大
  3. 代理模式强调代理过程的管制

优缺点

长处

  • 是继承的补充,比继承灵便

    • 不扭转原有对象的状况下,能疾速扩大性能
  • 能够通过不同装璜器类和装璜器类的排列组合实现不同成果

毛病

  • 会呈现更多的代码,更多的类
  • 嵌套调用代码变得复杂了

问题

认真比照一下装璜者模式和代理模式结构图,想一想你怎么辨别它们,从这里给你什么启发。

  • 装璜器次要强调的是本人,扩大的是本人的能力,并且是对继承的扩大
  • 代理模式则是为了实现对象的管制,提供一个代理对象进去,通过代理对象来管制原有对象的援用
  • 装璜模式是为装璜的对象加强性能;而代理模式对代理的对象施加管制,然而并不象自身的性能进行加强;

剖析一下 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 吧

正文完
 0