设计模式篇-(2)-结构模式之: 适配/装饰/代理模式

上一篇:设计模式篇-(1)-面向对象的七大设计原则


2.1 适配器和装饰器的区别

1. 适配器

  1. 适配器是把一个API包装成另一个API;
  2. 适配者和被适配者实现的接口不同;

2. 装饰器

  1. 装饰器是保留被包装的原API;
  2. 装饰者和被装饰者实现相同的接口(只是增加更多)

2.2 适配器和装饰器的相同点

1. 都是结构模式

2. 都是wrapper模式

2.3 wrapper模式(适配器/装饰器)与代理模式的对比

1. wrapper模式

  1. wrapper是把一个API转成另一个API(适配), 或者用另一个API来增强原有的API(装饰);

2. 代理模式

  1. 代理是用一个API来替代+增强原有的API;

代理分两种: 通过接口代理和通过类

3. 代理模式-接口型(java中动态代理)

代理类需要实现和被代理的类相同的接口, 然后在代理类实现中使用和增强被代理的原API;

4. 代理模式-类(CGLib代理)

代理类要代理的目标没有接口, 这样的话, 代理类需要继承被代理类, 来做代理和增强API的逻辑;

2.4 适配器-案例-(java.io包)

2.4.1 InputStream和OutputStream适配:

  • ByteArrayInputStream
  • FileInputStream
  • BufferedInputStream
  • PipedInputStream
  • StringBufferInputStream(无对应的Output)
  • ByteArrayOutputStream
  • FileOutputStream
  • BufferedOutputStream
  • PipedOutputStream
  1. ByteArrayInputStream
public ByteArrayInputStream extends InputStream {
    protected byte buf[];
    .....
}
用一个 byte buf[] byte数组来适配成 InputStream 流处理器的接口;
  1. FileInputStream
public FileInputStream extends InputStream{
    /* File Descriptor - handle to the open file */
    private final FileDescriptor fd;
    ...
}
用一个 FileDescriptor 来适配成一个 InputStream 流处理器的接口;
  1. StringBufferInputStream
@Deprecated
public class StringBufferInputStream extends InputStream{
    /**
     * The string from which bytes are read.
     */
    protected String buffer;
    ...
}
用一个 String 来适配成一个 InputStream 流处理器的接口;
  1. BufferedInputStream
public class BufferedInputStream extends FilterInputStream {

    private static int DEFAULT_BUFFER_SIZE = 8192;

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;

    /**
     * The internal buffer array where the data is stored. When necessary,
     * it may be replaced by another array of a different size.
     */
    protected volatile byte buf[];
ByteArrayInputStream 类似, 用一个 byte buf[] byte数组来适配成 InputStream 流处理器的接口;
  1. PipedInputStream
public class PipedInputStream extends InputStream {
    boolean closedByWriter = false;
    volatile boolean closedByReader = false;
    boolean connected = false;

        /* REMIND: identification of the read and write sides needs to be more sophisticated.
           Either using thread groups (but what about pipes within a thread?)
           or using finalization (but it may be a long time until the next GC).
         */
    Thread readSide;
    Thread writeSide;

    private static final int DEFAULT_PIPE_SIZE = 1024;

    /**
     * The default size of the pipe's circular input buffer.
     * @since   JDK1.1
     */
    // This used to be a constant before the pipe size was allowed
    // to change. This field will continue to be maintained
    // for backward compatibility.
    protected static final int PIPE_SIZE = DEFAULT_PIPE_SIZE;

    /**
     * The circular buffer into which incoming data is placed.
     * @since   JDK1.1
     */
    protected byte buffer[];
使用 一读一写两个线程一个 byte数组, 来适配成 InputStream 流处理器的接口;

Output部分略去代码说明

2.4.2. Reader和Writer适配

  • BufferedReader
  • CharArrayReader
  • StringReader
  • PipedReader
  • BufferedWriter
  • CharArrayWriter
  • StringWriter
  • PipedWriter

略去代码

2.4.3. byte流到char流的适配

  • InputStreamReader
  • OutputStreamWriter
public class InputStreamReader extends Reader {
    private final StreamDecoder sd;
    ...
}
sun.nio.cs.StreamDecoder 适配 InputStream为Reader, 字节到字符
public class OutputStreamWriter extends Writer {
    private final StreamEncoder se;
    ...
}
sun.nio.cs.StreamEncoder适配 InputStream为Reader, 字节到字符

2.5 装饰器-案例(java.io包)

2.5.1 装饰器-BufferedReader

BufferedReader br = new BufferedReader(new FileReader("f.txt"));
  1. br除了有文件读取和转换功能,还提供了缓存读取(buffered)功能;
  2. br增加了readLine()方法,可以逐行的读取文件。这里增加了Reader类没有的功能, 有些破坏装饰器模式的意味 感觉好像有转为适配器模式的影子;

所以, 只能称呼 BufferedReader: 是一个装饰类, 但不是一个100%的装饰类, 因为他增加了 readLine()新方法;

一个装饰类实现的新方法越多, 偏离纯装饰类的就越远!

你可能感兴趣的