I have read in wikipedia that Decorator pattern is used for .Net and Java IO classes.
Can anybody explain how this is being used? And what is the benefit of it with a possible example?
There is an example of Windows forms on wikipedia but I want to know how it happens with Java IO classes.
The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new Decorator class that wraps the original class.
Example. The Decorator attaches additional responsibilities to an object dynamically. The ornaments that are added to pine or fir trees are examples of Decorators. Lights, garland, candy canes, glass ornaments, etc., can be added to a tree to give it a festive look.
Decorator Pattern This is a common pattern found in Java's original IO classes used for reading and writing to sources outside JVM. For example, the InputStream and the OutputStream classes and their subclasses extensively use this pattern in their read and write operations.
The Decorator Pattern allows class behavior to the decorated dynamically. It's a structural design pattern as it's used to form large object structures across many disparate objects. The concept of decorator is that it adds additional attributes to an object dynamically.
InputStream
is an abstract class. Most concrete implementations like BufferedInputStream
, GzipInputStream
, ObjectInputStream
, etc. have a constructor that takes an instance of the same abstract class. That's the recognition key of the decorator pattern (this also applies to constructors taking an instance of the same interface).
When such a constructor is used, all methods will delegate to the wrapped instance, with changes in the way the methods behave. For example, buffering the stream in memory beforehand, decompressing the stream beforehand or interpreting the stream differently. Some even have additional methods that finally also delegate further to the wrapped instance. Those methods decorate the wrapped instance with extra behaviour.
Let's say that we have a bunch of serialized Java objects in a Gzipped file and that we want to read them quickly.
First open an inputstream of it:
FileInputStream fis = new FileInputStream("/objects.gz");
We want speed, so let's buffer it in memory:
BufferedInputStream bis = new BufferedInputStream(fis);
The file is gzipped, so we need to ungzip it:
GzipInputStream gis = new GzipInputStream(bis);
We need to unserialize those Java objects:
ObjectInputStream ois = new ObjectInputStream(gis);
Now we can finally use it:
SomeObject someObject = (SomeObject) ois.readObject(); // ...
The benefit is that you have a lot of freedom to decorate the stream using one or more various decorators to suit your needs. That's much better than having a single class for every possible combination like ObjectGzipBufferedFileInputStream
, ObjectBufferedFileInputStream
, GzipBufferedFileInputStream
, ObjectGzipFileInputStream
, ObjectFileInputStream
, GzipFileInputStream
, BufferedFileInputStream
, etc.
Note that when you're about to close the stream, just closing the outermost decorator is sufficient. It will delegate the close call all the way to the bottom.
ois.close();
Let's understand components of Decorator pattern before going through java IO classes.
Decorator pattern has four components
The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new Decorator class that wraps the original class.
Now let's map these concepts to java.io pacakge classes.
Component:
InputStream :
This abstract class is the superclass of all classes representing an input stream of bytes.
Applications that need to define a subclass of InputStream must always provide a method that returns the next byte of input.
public abstract int read()
is an abstract method.
ConcreteComponent:
FileInputStream:
A FileInputStream obtains input bytes from a file in a file system. What files are available depends on the host environment.
FileInputStream is meant for reading streams of raw bytes such as image data. For reading streams of characters, consider using FileReader.
Examples of all ConcreteComponents of InputStream:
AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream
Decorator:
FilterInputStream:
A FilterInputStream contains some other input stream, which it uses as its basic source of data, possibly transforming the data along the way or providing additional functionality.
Please note that FilterInputStream
implements InputStream
=> Decorator implements Component as shown in UML diagram.
public class FilterInputStream extends InputStream
ConcreteDecorator:
BufferedInputStream
A BufferedInputStream adds functionality to another input stream-namely, the ability to buffer the input and to support the mark and reset methods.
Examples of all ConcreteDecorators:
BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream, DeflaterInputStream, DigestInputStream, InflaterInputStream, LineNumberInputStream, ProgressMonitorInputStream, PushbackInputStream
Working example code:
I have used BufferedInputStream
to read each character of a word, which has been stored in a text file a.txt
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt"))); while(bis.available()>0) { char c = (char)bis.read(); System.out.println("Char: "+c);; }
When to use this pattern:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With