Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for."— Presentation transcript:

1 Decorator Explained

2 Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for extending functionality Also Known As – Wrapper 2

3 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

4 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

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

6 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

7 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

8 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

9 Motivation 9

10 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

11 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

12 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

13 Structure 13

14 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

15 Collaborations Decorator forwards requests to its Component object. It may optionally perform additional operations before and after forwarding the request. 15

16 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

17 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

18 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

19 Starbuzz Coffee 19

20 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

21 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

22 Applying Decorator to Starbuzz We will perform the following steps 1.Take a DarkRoast object 2.Decorate it with a Mocha object 3.Decorate it with a Whip object 4.Call the cost() method and rely on delegation to add on the condiment costs 22

23 Applying Decorator to Starbuzz 23 Remember that DarkRoast inherits from Beverage and has a 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.

24 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

25 Class Structure for Starbuzz 25

26 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

27 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

28 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

29 Decorators (Condiments) // abstract base class CondimentDecorator is-a Beverage public 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

30 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

31 Calling Program class 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 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

32 Outputs 32

33 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 Pizza Store NyStyle Cheeze Pizza NyStyle Cheeze Pizza NyStyle Cheeze Pizza NyStyle Cheese Pizza Chicago Cheeze Pizza Chicago Cheeze Pizza Chicago Cheeze Pizza Chicago Cheese Pizza


Download ppt "Decorator Explained. Intent Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for."

Similar presentations


Ads by Google