Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators...

33
Decorator Explained

Transcript of Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators...

Page 1: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Decorator

Explained

Page 2: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Intent

• Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for extending functionality

• Also Known As – Wrapper

2

Page 3: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation

• Sometimes we want to add responsibilities to individual objects. A graphical user interface toolkit, for example,should let you add properties like borders or behaviors like scrolling to any user interface component

• One way to add responsibilities is with inheritance. Inheriting a border from another class puts a border around every subclass instance.

• This is inflexible, however, because the choice of border is made statically. A client can't control how and when to decorate the component with a border.

3

Page 4: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation• A more flexible approach is to enclose the

component in another object that adds the border

• The enclosing object is called a decorator• The decorator conforms to the interface of the

component it decorates so that its presence is transparent to the component's clients.

• The decorator forwards requests to the component and may perform additional actions (such as drawing a border) before or after forwarding.

4

Page 5: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation

• Transparency lets you nest decorators recursively, thereby allowing an unlimited number of added responsibilities

5

Page 6: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation• Suppose we have a TextView object that displays

text in a window.• TextView has no scroll bars by default, because we

might not always need them• When we do, we can use a ScrollDecorator to add

them• Suppose we also want to add a thick black border

around the TextView. We can use a BorderDecorator to add this as well

• We simply compose the decorators with the TextView to produce the desired results.

6

Page 7: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation

• The following object diagram shows how to compose a TextView object with BorderDecorator and ScrollDecorator objects to produce a bordered, scrollable text view

7

Page 8: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation

• The ScrollDecorator and BorderDecorator classes are subclasses or concrete classes of Decorator

• Decorator is an abstract class for visual components that decorate other visual components

8

Page 9: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation

9

Page 10: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation

• VisualComponent is the abstract class for visual objects. It defines their drawing and event handling interface.

• Decorator class simply forwards draw requests to its component, and Decorator subclasses can extend this operation.

• Decorator subclasses are free to add operations for specific functionality

• For example, ScrollDecorator's ScrollTo operation lets other objects scroll the interface if they know there happens to be a ScrollDecorator object in the interface.

10

Page 11: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Motivation

• The important aspect of this pattern is that it lets decorators appear anywhere a VisualComponent can

• That way clients generally can't tell the difference between a decorated component and an undecorated one, and so they don't depend at all on the decoration

11

Page 12: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Applicability

• Use Decorator– To add responsibilities to individual objects

dynamically and transparently, that is, without affecting other objects.

– For responsibilities that can be withdrawn.– When extension by sub-classing is impractical.

Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for sub-classing

12

Page 13: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Structure

13

Page 14: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Participants

• Component (VisualComponent)– defines the interface for objects that can have

responsibilities added to them dynamically.• ConcreteComponent (TextView)– defines an object to which additional responsibilities can be

attached.• Decorator– maintains a reference to a Component object and defines an

interface that conforms to Component's interface• ConcreteDecorator (BorderDecorator, ScrollDecorator)– adds responsibilities to the component.

14

Page 15: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Collaborations

• Decorator forwards requests to its Component object.

• It may optionally perform additional operations before and after forwarding the request.

15

Page 16: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Consequences• More flexibility than static inheritance

– With decorators, responsibilities can be added and removed at run-time simply by attaching and detaching them. In contrast, inheritance requires creating a new class for each additional responsibility (e.g., BorderedScrollableTextView, BorderedTextView). This gives rise to many classes and increases the complexity of a system.

• Avoids feature-laden classes high up in the hierarchy– Decorator offers a pay-as-you-go approach to adding

responsibilities. Instead of trying to support all foreseeable features in a complex, customizable class, you can define a simple class and add functionality incrementally with Decorator objects. Functionality can be composed from simple pieces. As a result, an application needn't pay for features it doesn't use. It's also easy to define new kinds of Decorators independently from the classes of objects they extend, even for unforeseen extensions

16

Page 17: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Consequences

• A decorator and its component aren't identical– A decorator acts as a transparent enclosure. But from

an object identity point of view, a decorated component is not identical to the component itself

• Lots of little objects– A design that uses Decorator often results in systems

composed of lots of little objects that all look alike. Although these systems are easy to customize by those who understand them, they can be hard to learn and debug

17

Page 18: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Implementation Issues• Interface conformance - A decorator object's

interface must conform to the interface of the component it decorates. ConcreteDecorator classes must therefore inherit from a common class.

• Omitting the abstract Decorator class - There's no need to define an abstract Decorator class when you only need to add one responsibility. In that case, you can merge Decorator's responsibility for forwarding requests to the component into the ConcreteDecorator

18

Page 19: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Starbuzz Coffee

19

Page 20: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Open-Closed Design Principle

•Classes should be open for extension, but closed for modification

•Our goal is to allow classes to be easily extended to incorporate new behavior without modifying existing code.

•We can get designs that are resilient to change and flexible enough to take on new functionality to meet changing requirements

•Let’s apply decorator pattern on starbuzz case.

20

Page 21: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Applying Decorator to Starbuzz

• Okay, we’ve seen that representing our beverage plus condiment pricing scheme with inheritance has not worked out very well – we get class explosions, rigid designs, or we add functionality to the base class that isn’t appropriate for some of the subclasses

• So, here’s what we’ll do instead: we’ll start with a beverage and decorate it with the condiments at runtime. For example, if the customer wants a Dark Roast with Mocha and Whip then,

21

Page 22: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Applying Decorator to Starbuzz

• We will perform the following steps1. Take a DarkRoast object2. Decorate it with a Mocha object3. Decorate it with a Whip object4. Call the cost() method and rely on delegation to

add on the condiment costs

22

Page 23: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Applying Decorator to Starbuzz

23

Remember that DarkRoast inherits from Beverage and hasa cost() method that computes the cost of the drink

So, Mocha has a cost() method too, and through polymorphism we can treat any Beverage wrapped in Mocha as a Beverage, too (because Mocha is a subtype of Beverage)

So, a DarkRoast wrapped in Mocha and Whip is still a Beverage and we can do anything with it we can do with a DarkRoast, including call its cost() method.

Page 24: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Calculating Cost of Starbuzz Coffee

• Now it’s time to compute the cost for the customer. We do this by calling cost() on the outermost decorator, Whip, and Whip is going to delegate computing the cost to the objects it decorates. Once it gets a cost, it will add on the cost of the Whip.

24

Page 25: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Class Structure for Starbuzz

25

Page 26: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Some Important Facts

• So here we’re using inheritance to achieve the type matching , but we aren’t using inheritance to get behavior

• When we compose a decorator with a component, we are adding new behavior. We are acquiring new behavior not by inheriting it from a superclass, but by composing objects together.

26

Page 27: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Code for Starbuzz…Let’s define the abstract class Beverage

public abstract class Beverage{

protected String m_description;

// get a description of the beverage public virtual String Description { get { return m_description; } }

// calculate cost of the beverage public abstract double Cost();

}

27

Page 28: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Concrete Beverage Classes// HouseBlend coffee implements

Beverage

public class HouseBlend : Beverage{ // Constructor public HouseBlend() {

m_description = "House Blend"; }

// calculate base cost of House Blend public override double Cost()

{ return 0.89; }}

// DarkRoast coffee implements Beverage

public class DarkRoast : Beverage{ // Constructor public DarkRoast() {

m_description = "Dark Roast"; }

// calculate base cost of Dark Roast public override double Cost()

{ return 1.00; }}

28

Page 29: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Decorators (Condiments)// abstract base class CondimentDecorator is-a Beveragepublic abstract class CondimentDecorator : Beverage {}

public class Mocha : CondimentDecorator{

private Beverage m_beverage;public Mocha(Beverage beverage) {

this.m_beverage = beverage; } // getter implements abstract class Description public override String Description{ get{return m_beverage.Description + ", Mocha“; } } // get the Cost of the condiment plus the base-cost of the original beverage public override double Cost() { return 0.20 + m_beverage.Cost(); }} 29

Page 30: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Decorators (Condiments)public class Milk : CondimentDecorator{

private Beverage m_beverage;public Milk(Beverage beverage)

{ this.m_beverage = beverage; }// getter implements abstract class public override String Description{Get{return m_beverage.Description + ", Milk"; } }// get the Cost of the condiment plus the

base-//cost of the original beverage public override double Cost() { return 0.10 + m_beverage.Cost(); }}

public class Whip : CondimentDecorator{private Beverage m_beverage;public Whip(Beverage beverage) { this.m_beverage = beverage; } // getter implements abstract class Description public override String Description { get{return m_beverage.Description + ", Whip"; } } // get the Cost of the condiment plus the base-//

cost of the original beverage public override double Cost() { return 0.15 + m_beverage.Cost(); }}

30

Page 31: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Calling Programclass Program{ static void Main(string[] args) { //Ordering an Espresso Beverage beverage = new Espresso(); Console.WriteLine("Your Order is: " + beverage.Description + " & would Cost: " + beverage.Cost()); Console.ReadLine(); //Ordering a Darkroast with Double Mocha and Whip Beverage beveragetwo = new DarkRoast(); beveragetwo = new Mocha(beveragetwo); beveragetwo = new Mocha(beveragetwo); beveragetwo = new Whip(beveragetwo); Console.WriteLine("Your Order is: " + beveragetwo.Description + " & would Cost: " +

beveragetwo.Cost()); Console.ReadLine(); //Ordering a Houseblend with Soye Mocha and Whip Beverage beveragethree = new HouseBlend(); beveragethree = new Soye(beveragethree); beveragethree = new Mocha(beveragethree); beveragethree = new Whip(beveragethree); Console.WriteLine("Your Order is: " + beveragethree.Description + " & would Cost: " +

beveragethree.Cost()); Console.ReadLine(); }} 31

Page 32: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Outputs

32

Page 33: Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for.

Quiz # 2

Looking at the Diagram, please answer the two questions. 1. What’s wrong with the design. How can we make this design more

flexible?2. Please make a diagram of the changed design after applying the

appropriate design principle?33

PizzaStore

NyStyleCheezePizza

NyStyleCheezePizza

NyStyleCheezePizza

NyStyleCheesePizza

ChicagoCheezePizza

ChicagoCheezePizza

ChicagoCheezePizza

ChicagoCheesePizza