步骤 1

创建一个接口:

Shape.java

1 public interface Shape {
2    void draw();
3 }

步骤 2

创建实现接口的实体类。

Rectangle.java

1 public class Rectangle implements Shape {
2  
3    @Override
4    public void draw() {
5       System.out.println("Shape: Rectangle");
6    }
7 }

Circle.java

1 public class Circle implements Shape {
2  
3    @Override
4    public void draw() {
5       System.out.println("Shape: Circle");
6    }
7 }

步骤 3

创建实现了 Shape 接口的抽象装饰类。

ShapeDecorator.java

 1 public abstract class ShapeDecorator implements Shape {
 2    protected Shape decoratedShape;
 3  
 4    public ShapeDecorator(Shape decoratedShape){
 5       this.decoratedShape = decoratedShape;
 6    }
 7  
 8    public void draw(){
 9       decoratedShape.draw();
10    }  
11 }

步骤 4

创建扩展了 ShapeDecorator 类的实体装饰类。

RedShapeDecorator.java

 1 public class RedShapeDecorator extends ShapeDecorator {
 2  
 3    public RedShapeDecorator(Shape decoratedShape) {
 4       super(decoratedShape);     
 5    }
 6  
 7    @Override
 8    public void draw() {
 9       decoratedShape.draw();         
10       setRedBorder(decoratedShape);
11    }
12  
13    private void setRedBorder(Shape decoratedShape){
14       System.out.println("Border Color: Red");
15    }
16 }

步骤 5

使用 RedShapeDecorator 来装饰 Shape 对象。

DecoratorPatternDemo.java

 1 public class DecoratorPatternDemo {
 2    public static void main(String[] args) {
 3  
 4       Shape circle = new Circle();
 5       ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
 6       ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
 7       //Shape redCircle = new RedShapeDecorator(new Circle());
 8       //Shape redRectangle = new RedShapeDecorator(new Rectangle());
 9       System.out.println("Circle with normal border");
10       circle.draw();
11  
12       System.out.println("
Circle of red border");
13       redCircle.draw();
14  
15       System.out.println("
Rectangle of red border");
16       redRectangle.draw();
17    }
18 }

步骤 6

执行程序,输出结果:

Circle with normal border
Shape: Circle

Circle of red border
Shape: Circle
Border Color: Red

Rectangle of red border
Shape: Rectangle
Border Color: Red

装饰器模式在Java I/O系统中的实现

   前面总结了这么多,再从大神们的作品中找一个实际应用例子吧,毕竟那是经历实战检验的,肯定是有道理的。嗯,在平时的留意中我发现Java I/O系统的设计中用到了这一设计模式,因为Java I/O类库需要多种不同功能的组合。这里我就以InputStream为例简单说明一下,同样我们还是来看一下其类图:

  InputStream作为抽象构件,其下面大约有如下几种具体基础构件,从不同的数据源产生输入:

  • ByteArrayInputStream,从字节数组产生输入;
  • FileInputStream,从文件产生输入;
  • StringBufferInputStream,从String对象产生输入;
  • PipedInputStream,从管道产生输入;
  • SequenceInputStream,可将其他流收集合并到一个流内;

  FilterInputStream作为装饰器在JDK中是一个普通类,其下面有多个具体装饰器比如BufferedInputStream、DataInputStream等。我们以BufferedInputStream为例,使用它就是避免每次读取时都进行实际的写操作,起着缓冲作用。我们可以在这里稍微深入一下,站在源码的角度来管中窥豹。

  FilterInputStream内部封装了基础构件:

protected volatile InputStream in;

  而BufferedInputStream在调用其read()读取数据时会委托基础构件来进行更底层的操作,而它自己所起的装饰作用就是缓冲,在源码中可以很清楚的看到这一切:

复制代码
    public synchronized int read() throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return getBufIfOpen()[pos++] & 0xff;
    }


    private void fill() throws IOException {
        byte[] buffer = getBufIfOpen();
        if (markpos < 0)
            pos = 0;            /* no mark: throw away the buffer */
        else if (pos >= buffer.length)  /* no room left in buffer */
            if (markpos > 0) {  /* can throw away early part of the buffer */
                int sz = pos - markpos;
                System.arraycopy(buffer, markpos, buffer, 0, sz);
                pos = sz;
                markpos = 0;
            } else if (buffer.length >= marklimit) {
                markpos = -1;   /* buffer got too big, invalidate mark */
                pos = 0;        /* drop buffer contents */
            } else if (buffer.length >= MAX_BUFFER_SIZE) {
                throw new OutOfMemoryError("Required array size too large");
            } else {            /* grow buffer */
                int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
                        pos * 2 : MAX_BUFFER_SIZE;
                if (nsz > marklimit)
                    nsz = marklimit;
                byte nbuf[] = new byte[nsz];
                System.arraycopy(buffer, 0, nbuf, 0, pos);
                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
                    throw new IOException("Stream closed");
                }
                buffer = nbuf;
            }
        count = pos;
        // 看这行就行了,委托基础构件来进行更底层的操作
        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
        if (n > 0)
            count = n + pos;
    }

    private InputStream getInIfOpen() throws IOException {
        InputStream input = in;
        if (input == null)
            throw new IOException("Stream closed");
        return input;
    }
复制代码

  这部分的代码很多,这里我们没有必要考虑这段代码的具体逻辑,只需要看到在BufferedInputStream的read方法中通过getInIfOpen()获取基础构件从而委托其进行更底层的操作(在这里是读取单个字节)就可以说明本文所要说的一切了。

  至于I/O类库中的其他设计诸如OutputStream、Writer、Reader,是一致的,这里就不再赘述了。