Design Pattern: Decorator Pattern

Decorator Pattern

 

1) Motivation:

    Extending an object's functionality can be done statically (at compile time) by using inherientence. However it might be necessary to extend an object's functionality dynamically(at runtime) as an object is used.

 

    Consider the typical example of a graphical window. To extend the functionality of a graphical window, for example by adding a frame to the window, would require extending the window class to create a FrameWindow class. To create a FrameWindow, it is necessary to create an object of FrameWindow class. However, it would be impossible to start with a plain window and to extend its functionality at runtime to become a framed window.

 

2) Intent:

    The intent of this pattern is to add additional responsibilty dynamically(at runtime) to an object.

 

3) Implementation:

 


    1> Component:

            Interface for objects that can have responsibilities added to them dynamically.

    2> ConcreteComponent:

            Defines an object to which additional responsibilites can be added.

    3> Decorator:

            Maintains a reference to a Component object and defines an interface that conforms to Component's interface.

    4> ConcreteDecorator:

            Extends the functionality of the Component by adding state or adding behavior. 

 

4) Description:

    The decorator pattern applies when there is a need to dynamically add as well as remove responsibilites to a class, and when subclassing would be impossible due to the large number of subclasses that could result.

 

5) Applicability & Examples:

    Example: Extending capabilities of a Graphical Window at runtime



package edu.xmu.oop.decorator;

public interface Window {
    public void renderWindow();
}
package edu.xmu.oop.decorator;

public class SimpleWindow implements Window {
    public void renderWindow() {
	System.out.println(String.format("Start render for: [%s]", this));
	System.out.println(String.format("Finished render for: [%s]", this));
    }
}
package edu.xmu.oop.decorator;

public class DecoratedWindow implements Window {
    private Window windowReference;

    public DecoratedWindow(Window windowReference) {
	super();
	this.windowReference = windowReference;
    }

    public void renderWindow() {
	windowReference.renderWindow();
    }
}
package edu.xmu.oop.decorator;

public class ScrollableWindow extends DecoratedWindow {

    private String scrollBarObjectRepresentation;

    public ScrollableWindow(Window windowReference,
	    String scrollBarObjectRepresentation) {
	super(windowReference);
	this.scrollBarObjectRepresentation = scrollBarObjectRepresentation;
    }

    @Override
    public void renderWindow() {
	renderScrollBar();
	super.renderWindow();
    }

    private void renderScrollBar() {
	System.out.println(String.format("Start renderScrollBar for: [%s]",
		this));
	System.out.println(scrollBarObjectRepresentation);
	System.out.println(String.format("Finished renderScrollBar for: [%s]",
		this));
    }
}
package edu.xmu.oop.decorator;

public class FramableWindow extends DecoratedWindow {

    public FramableWindow(Window windowReference) {
	super(windowReference);
    }

    @Override
    public void renderWindow() {
	addFrame();
	super.renderWindow();
    }

    private void addFrame() {
	System.out.println(String.format("Start addFrame for: [%s]", this));
	System.out.println(String.format("Finished addFrame for: [%s]", this));
    }
}
package edu.xmu.oop.decorator;

import org.junit.Test;

public class WindowTest {
    private Window window;

    @Test
    public void renderWindowTest() {
	window = new SimpleWindow();
	window.renderWindow();
	System.out.println("======================================");

	window = new FramableWindow(window);
	window.renderWindow();
	System.out.println("======================================");

	window = new ScrollableWindow(window, "ScrollBar");
	window.renderWindow();
    }
}

 

    Example: Java I/O Stream

 

package edu.xmu.oop.decorator;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.LineNumberInputStream;

import org.junit.Test;

@SuppressWarnings("deprecation")
public class InputStreamTest {
    @Test
    public void testRead() throws IOException {
	LineNumberInputStream inputStream = new LineNumberInputStream(
		new BufferedInputStream(new FileInputStream(new File(
			"src/test/resources/test.dat"))));
	while (-1 != inputStream.read()) {
	    System.out.println(inputStream.getLineNumber());
	}
	inputStream.close();
    }
}

 

6) Related Patterns:

    1> Adapter Pattern: A decorator is different from an adapter in that a Decorator changes object's responsibilites, while an Adapter changes object interfaces.

    2> Composite Pattern: A decorator can be viewed as a degenerate composite with only one component. However, a decorator adds additional responsibilites.

 

7) Consequences:

    1> Decoration is more convenient for adding functionalities to objects instead of entire class at runtime. With Decoration it is also possible to remove the added functionalities dynamically.

    2> Decoration added functionalities to object at runtime which would make debugging system functionality harder which just like Proxy Pattern.

 

 

Reference Links:

1) http://www.oodesign.com/decorator-pattern.html

2) http://en.wikipedia.org/wiki/Decorator_pattern

3) http://stackoverflow.com/questions/3068912/what-is-the-most-used-pattern-in-java-io

4) http://oreilly.com/catalog/hfdesignpat/chapter/ch03.pdf

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值