Back Home Up Next


1 Purpose

2 Problem Description

3 Domain Definitions

4 Elisa Components

1  Purpose

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. They are also known as Wrappers.


2  Problem Description

Sometimes we want to add responsibilities to individual objects, not to an entire class. 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.

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. Transparency lets you nest decorators recursively, thereby allowing an unlimited number of added responsibilities.

For example, 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 result.

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

The ScrollDecorator and BorderDecorator classes are subclasses of Decorator, an abstract class for visual components that decorate other visual components.

VisualComponent is the abstract class for visual objects. It defines their drawing and event handling interface. Note how the Decorator class simply forwards draw requests to its component, and how 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. 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.

3  Domain Definitions

We will transform the top-level relations into a set of corresponding domain definitions:

VisualComponent = TextView | Decorator

TextView = . . .

Decorator =  ScrollDecorator | BorderDecorator

ScrollDecorator = . . . scrollPosition + . . .

BorderDecorator = . . . borderWidth + . . .

The next step is to translate the domain definitions into a number of Elisa components. In addition, we will use skeletons of definitions as shown in the preceding class relationships.

4  Elisa components 

Based on the domain definitions a set of related components are derived. The following component implements the the first domain definition  VisualComponent = TextView | Decorator:

component VisualComponents;
type VisualComponent = category(TextView, Decorator);

type Component = VisualComponent;  

     Draw(VisualComponent) -> Status;
        . . .

            <<implementations of >>
     Draw(TextView:textview) = Draw(textview);
     Draw(decorator) = Draw(Decorator:decorator);
        . . .

end component VisualComponents;

The following component is a skeleton example of a TextView component:

component TextViews;
type TextView;
     CreateTextView( ) -> TextView;
     Draw(TextView)    -> Status;

      . . .
            <<implementations of >>
     CreateTextView( )= TextView:[...];
     Draw(textview)   = ...;

      . . .
end component TextViews;

The following component is an example of a component for Decorator =  ScrollDecorator | BorderDecorator:

component Decorators;
type Decorator = category(ScrollDecorator, BorderDecorator);

     Draw(Decorator) -> Status;
        . . .

     Draw(ScrollDecorator:scrollDecorator) = Draw(scrollDecorator);

     Draw(BorderDecorator:borderDecorator) = Draw(borderDecorator);

      . . .

end component Decorators;


The following component is a skeleton implementation of ScrollDecorator =  . . .  + scrollPosition:  

component ScrollDecorators;
type ScrollDecorator;
     CreateScrollDecorator(Decorator) -> ScrollDecorator;
     Draw(ScrollDecorator)            -> Status;

     ScrollTo(ScrollDecorator, Position=integer) -> nothing;

                .  .  .  
            <<implementations of >>
     CreateScrollDecorator(decorator) = ScrollDecorator:[ decorator; scrollPosition:= 0;...];
     Draw(scrolldecorator) = [...Draw(scrolldecorator.decorator)...];

     ScrollTo(scrolldecorator, position) = [ ... scrolldecorator.scrollPosition:= position ... ];

      . . .
end component ScrollDecorators; 


The following component is a skeleton implementation of  BorderDecorator =  . . .  + borderWidth:

component BorderDecorators;
type BorderDecorator;
     CreateBorderDecorator(Decorator) -> BorderDecorator;
     Draw(BorderDecorator)            -> Status;

     DrawBorder(BorderDecorator)      -> nothing; 

        .  .  .  
            <<implementations of >>
     CreateBorderDecorator(decorator) = BorderDecorator:[ decorator; borderWidth = 10; ...];
     Draw(borderdecorator) = [...Draw(borderdecorator.decorator)...];

     DrawBorder(borderdecorator) = [...Draw(borderdecorator.decorator); DrawBorder(borderdecorator)...]; 

       . . .
end component BorderDecorators;



Back Home Up Next

  Part 5: Design Patterns   Decorator


Home | Highlights of Elisa | Integrating Different Paradigms | Getting Started with Elisa | Demo's  | What is Domain Orientation | Bibliography | Copyright | News | Contact | Contents

Language Description:

Lexical Elements | Basic Data Types and Expressions | Definitions | Streams | Backtracking | Statements and Special Expressions | Arrays | Lists | Descriptors | Components | Collections | Generic Components | Terms | Categories | Types | Built-in Definitions | Higher-order Definitions | External Interfaces | Index 

Data Structures: Sequences | Examples involving Lists | Trees | Graphs | Searching State Spaces | Language Processing | Knowledge Representations
Domain Modeling:

Domain Modeling | Concepts | Domain Definitions | Domain Operations | Domain Implementations | Systems | Case study: an Order processing system | Case study: an Airport Support system | Domain Orientation versus Object Orientation

Design Patterns:

Introduction | Abstract Factory | Builder | Factory Method | Prototype | Singleton | Adapter | Bridge | Composite | Decorator | Facade | Flyweight | Proxy | Chain of Responsibility | Command | Interpreter | Iterator | Mediator | Memento | Observer | State | Strategy | Template Method | Visitor 


click tracking


Send me your comments


This page was last modified on 04-12-2012 11:12:26   

free hit counter