Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Cases and Examples of GoF Decorator Pattern for IO

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.

like image 431
DarthVader Avatar asked Jun 16 '11 02:06

DarthVader


People also ask

When would you use the GOF Decorator design pattern?

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.

Where do we use Decorator design pattern explain with example?

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.

How does Decorator design pattern works in I O classes?

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.

What is the decorator pattern used for?

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.


2 Answers

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(); 

See also:

  • Examples of GoF Design Patterns in Java's core libraries
like image 167
BalusC Avatar answered Sep 27 '22 21:09

BalusC


Let's understand components of Decorator pattern before going through java IO classes.

enter image description here

Decorator pattern has four components

  1. Component: The Component defines the interface for objects that can have responsibilties added dynamically
  2. ConcreteComponent: It is simply an implementation of Component interface
  3. Decorator: The Decorator has a reference to a Component, and also conforms to the Component interface. Decorator is essentially wrapping the Component
  4. ConcreteDecorator: The ConcreteDecorator just adds responsibilities to the original Component.

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:

  1. Object responsibilities and behaviours should be dynamically added/removed
  2. Concrete implementations should be decoupled from responsibilities and behaviours
  3. When sub - classing is too costly to dynamically add/remove responsibilities
like image 34
Ravindra babu Avatar answered Sep 27 '22 22:09

Ravindra babu