Decorator pattern in Java IO

Decorator mode can be used to enhance the original method, for example, FileInputStream in Java IO has no caching and is slow to execute, We can implement cached IO stream methods by decorating FileInputStream with BufferedInputStream. In this vein, we’ll write a BufferedInputStream manually

public class BufferedInputStream extends FileInputStream {
    
    byte[] buffer = new byte[8192];
    
    @Override
    public int read(a){
    	// Call the parent class's read method to add caching logic}}Copy the code





public class BufferedInputStream {
    
    private InputStream inputStream;
    
    public BufferedInputStream(InputStream inputStream){
    	this.inputStream = inputStream;
    }
    
    byte[] buffer = new byte[8192];
    
    public int read(a){
    	// Call the parent class's read method to add caching logic
    }
    
    // Other methods that do not require enhancement
    public void other(a){ inputStream.other(); }}Copy the code

If you use a combination method, all other methods that don’t need to be enhanced will have to be completely overwritten, calling the combined method in the method body to return, so the code is very repeatable, so it uses a very clever method, which is combination + inheritance, and the inherited FileInputStream will not work. If you inherit InputStream, you still have to rewrite and call all the methods in the composite class. The JDK’s source code is derived from FilterInputStream. How does it solve this problem

public class FilterInputStream extends InputStream {
    
    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    public int read(a) throws IOException {
        return in.read();
    }

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
        return in.read(b, off, len);
    }

    public long skip(long n) throws IOException {
        return in.skip(n);
    }

    // The other methods are similar in that they call methods in the composite class
}
Copy the code

So this is a very clever design, you put the composite class into FilterInputStream, FilterInputStream reimplements all the methods in the class composite class, and then BufferedInputStream inherits it, So BufferedInputSteam just enhances the methods that need caching, not the other methods that don’t need to be enhanced. Java IO includes not only caching enhancements, but ZipInputStream compression streams, DataInputStream data streams, and so on, which inherit FilterInputStream ‘so that these classes only care about the methods they need to enhance

The decorator pattern is special over the proxy pattern

If you compare the decorator pattern with the static proxy pattern, you will find that they are both enhancements to the original method. What is special about the decorator pattern? 2. The decorator wrapper classes inherit from the same object FilterInputStream or FilterOutputStream, which in turn inherit from InputStream or OutputStream. So they can be nested, as shown below

FileInputStream in = new FileInputStream("D://xxx.xml");
BufferedInputStream buf = new BufferedInputStream(in);
ZipInputStream zip = new ZipInputStream(buf);
Copy the code