Design Pattern - Structural Patterns - Decorator Pattern

50 篇文章 0 订阅
37 篇文章 0 订阅

2007

Section 4, Chapter 4


Decorator Pattern


Concept

The Decorator pattern gives us a way to use inheritance as a conditional add-on. Inheritance is used in the pattern in such a way as to make each inherited class be a sum of all the parts.


Use

One use is to provide flexible inheritance. We can cast our decorator to be of the base type of component, which can give us all the same basic functionality we might have in a non-decorated control, but allows us to add desired functionality in an ad-hoc fashion.

By making a control a decorator we add all the control's functions and a few desired new ones, or, if we wish not to have the new functionality, we can simply use the non-decorated control.


Design

The Decorator pattern has four main parts: 

  • Component: usually an abstract class that holds the base functionality for both the non-decorated classes as well as the decorated ones. non-decorated means the existing component without a decorator class applied to;
  • Concrete Component: non-decorated implementation class of the component, which we can instance without a decorator;
  • Decorator: the abstract class that inherits from the component and holds an encapsulated instance of our desired concrete component;
  • Concrete Decorator: the implementation class with the added functionality desired for our decorator.



Illustration


Suppose we have the code in place as below:

abstract class WindowControl
{
	public int Height {get,set}
	public int Width {get,set}
	public int XCoord {get,set}
	public int YCoord {get,set}

	public abstract void Render();
}

class TextBox : WindowControl
{
	public string Value {get,set}

	public TextBox(int height, int width, int x, int y)
	{
		this.Height = height;
		this.Width = width;
		this.XCoord = x;
		this.YCoord = y;
	}

	public override void Render()
	{
		// ...
	}
	
}


If we need to add scroll bar functionality, we might add a new class inheriting TextBox, with the new functions:

public int ScrollBarWidth {get,set}
public int ScrollBarPosition {get,set}
	
public override void Render()
{
	if(_scrollBarWidth > 0 && _scrollBarPosition > 0)
	{
		Console.WriteLine("--Scroll Bar Width:" + _scrollBarWidth);
		Console.WriteLine("--Scroll Bar Position:" + _scrollBarPosition);
	}
	Console.WriteLine("--TextBox Height:"+this.Height);
	Console.WriteLine("--TextBox Width:"+this.Width);
	Console.WriteLine("--TextBox X Coord:"+this.XCoord);
	Console.WriteLine("--TextBox Y Coord:"+this.YCoord);
	Console.WriteLine("--TextBox Value:"+_value);
}


A better solution with decorator pattern is shown as:



abstract class ControlDecorator : WindowControl
{
	protected WindowControl underlyingControl;
	public ControlDecorator(WindowControl control)
	{
		underlyingControl = control;
	}
	public override void Render()
	{
		underlyingControl.Render();
	}
}

class TextBoxScrollDecorator : ControlDecorator
{
	private int _scrollBarWidth;
	private int _scrollBarPosition = 0;

	public TextBoxScrollDecorator(TextBox textBox) : base(textBox)
	{
	}

	public int ScrollBarWidth
	{
		get{return _scrollBarWidth;}
		set{_scrollBarWidth = value;}
	}
	
	public int ScrollBarPosition
	{
		get{return _scrollBarPosition;}
		set{_scrollBarPosition = value;}
	}
	
	public override void Render()
	{
		base.Render();
		Console.WriteLine("Added decorator values:");
		Console.WriteLine("--Scroll Bar Width:" +_scrollBarWidth);
		Console.WriteLine("--Scroll Bar Position:" +_scrollBarPosition);
	}
}


TextBox textBox = new TextBox(250,350,1200,300);
textBox.Value = "Some Text...";
textBox.Render();

TextBoxScrollDecorator scrollable = new
TextBoxScrollDecorator(textBox);
scrollable.ScrollBarPosition = 20;
scrollable.ScrollBarWidth = 10;
scrollable.Render();


December 2007

Section 1, Chapter 2


Design

A key implementation point in the Decorator pattern is that decorators both inherit the original class and contain an instantiation of it.

The beauty of this pattern is that:

  • The original object is unaware of any decorations.
  • There is no one big feature-laden class with all the options in it.
  • The decorations are independent of each other.
  • The decorations can be composed together in a mix-and-match fashion.




Component
An original class of objects that can have operations added or modified (there may be more than one such class);
IComponent
The interface that identifies the classes of objects that can be decorated (Component is one of these);
Operation
An operation in IComponent objects that can be replaced (there may be several operations);
IComponent: The interface that identifies the classes of objects that can be decorated (Component is one of these);
Decorator
A class that conforms to the IComponent interface and adds state and/or behavior (there may be more than one such class).



Decorator class includes two types of relationships with the IComponent interface:

Is-a
Decorator realizes the IComponent interface, therefore Decorator objects can be used wherever IComponent objects are expected. The Component class is also in an is-a relationship with IComponent, and therefore the client can use Component and Decorator objects interchangeably—the heart of the Decorator pattern.
Has-a
The Decorator instantiates one or more IComponent objects and that decorated objects can outlive the originals. The Decorator uses the component attribute (of type IComponent) to invoke any replacement Operation it might wish to override. This is the way the Decorator pattern achieves its objective.


Implementation


using System;

class DecoratorPattern {

	// Decorator Pattern Judith Bishop Dec 2006
	// Shows two decorators and the output of various
	// combinations of the decorators on the basic component
	interface IComponent {
		string Operation();
	}

	class Component: IComponent {
		public string Operation() {
			return "I am walking ";
		}
	}

	class DecoratorA: IComponent {
		IComponent component;

		public DecoratorA(IComponent c) {
			component = c;
		}

		public string Operation() {
			string s = component.Operation();
			s += "and listening to Classic FM ";
			return s;
		}
	}

	class DecoratorB: IComponent {
		IComponent component;
		public string addedState = "past the Coffee Shop ";

		public DecoratorB(IComponent c) {
			component = c;
		}

		public string Operation() {
			string s = component.Operation();
			s += "to school ";
			return s;
		}

		public string AddedBehavior() {
			return "and I bought a cappuccino ";
		}
	}

	class Client {

		static void Display(string s, IComponent c) {
			Console.WriteLine(s + c.Operation());
		}

		static void Main() {
			Console.WriteLine("Decorator Pattern\n");

			IComponent component = new Component();
			Display("1. Basic component: ", component);
			Display("2. A-decorated : ", new DecoratorA(component));
			Display("3. B-decorated : ", new DecoratorB(component));
			Display("4. B-A-decorated : ", new DecoratorB(
			new DecoratorA(component)));
			// Explicit DecoratorB
			DecoratorB b = new DecoratorB(new Component());
			Display("5. A-B-decorated : ", new DecoratorA(b));
			// Invoking its added state and added behavior
			Console.WriteLine("\t\t\t" + b.addedState + b.AddedBehavior());
		}
	}
}


Some highlights:

  • DecoratorA is fairly plain and simply implements the Operation by calling it on the component it has stored, then adding something to the string it returns.
  • DecoratorB offers some public addedState and addedBehavior as well.
  • In both implemented operations, the component's Operation method is called first, but this is not a requirement of the pattern.








The beauty of this pattern is that:



2016
Chapter




Vincent's Demonstration


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值