SDSU CS 696: Advanced OO
Spring Semester, 1997
Doc 14 Composite and Decorator

To Lecture Notes Index
San Diego State University -- This page last updated Apr 10, 1997
----------

Contents of Doc 14 Composite and Decorator


Composite slide # 1
...Example - Motivation slide # 1
...Issue: WidgetContainer Operations slide # 6
...Explicit Parent References slide # 7
...Applicability slide # 8
...Java Use of Composite - AWT Widgets slide # 9
Decorator slide # 11
...Solution 1 - Use Strategy slide # 12
...Solution 2 - Use Decorator slide # 13
...Applicability slide # 15
...Consequences slide # 15
...Implementation Issues slide # 16
...Java Example of Decorator - Streams slide # 17


Doc 14 Composite and Decorator Slide # 1
Composite

Example - Motivation

GUI Windows and GUI elements

How does the window hold and deal with the different items it has to manage?


Widgets are different that WidgetContainers


Doc 14 Composite and Decorator Slide # 2
Bad News Implementation

class Window
     {
     Buttons[] myButtons;
     Menus[] myMenus;
     TextAreas[] myTextAreas;
     WidgetContainer[] myContainers;
     
     public void update()
          {
          if ( myButtons != null )
               for ( int k = 0; k < myButtons.length(); k++ )
                    myButtons[k].refresh();
          if ( myMenus != null )
               for ( int k = 0; k < myMenus.length(); k++ )
                    myMenus[k].display();
          if ( myTextAreas != null )
               for ( int k = 0; k < myButtons.length(); k++ )
                    myTextAreas[k].refresh();
          if ( myContainers != null )
               for ( int k = 0; k < myContainers.length(); k++ )
                    myContainers[k].updateElements();
          etc.
          }
     public void fooOperation()
          {
          if ( blah ) etc.
          if ( blah ) etc.
          }
     }

Doc 14 Composite and Decorator Slide # 3
A Better Idea - Program to an interface

class Window
     {
     GUIWidgets[] myWidgets;
     WidgetContainer[] myContainers;
     
     public void update()
          {
          if ( myWidgets != null )
               for ( int k = 0; k < myWidgets.length(); k++ )
                    myWidgets[k].update();
          if ( myContainers != null )
               for ( int k = 0; k < myContainers.length(); k++ )
                    myContainers[k].updateElements();
          etc.
          }
     }

Doc 14 Composite and Decorator Slide # 4
The Composite Pattern - Version B


Component implements default behavior for widgets when possible

Button, Menu, etc overrides Component methods when needed

WidgetContainer will have to overrides all widgetOperations

class WidgetContainer
     {
     Component[] myComponents;
     
     public void update()
          {
          if ( myComponents != null )
               for ( int k = 0; k < myComponents.length(); k++ )
                    myComponents[k].update();
          }
     }


Issue: WidgetContainer Operations


Doc 14 Composite and Decorator Slide # 5

WidgetContainer operations tend to relate to adding, deleting and managing widgets

Should the WidgetContainer operations be declared in Component?

Pro - Transparency

Declaring them in the Component gives all subclasses the same interface

All subclasses can be treated alike. (?)


Con - Safety

Declaring them in WidgetContainer is safer

Adding or removing widgets to non-WidgetContainers is an error

What should be the proper response to added a TextArea to a button? throw an exception?

One out is to check the type of the object before using a WidgetContainer operation


Doc 14 Composite and Decorator Slide # 6

Explicit Parent References


Aid in traversing the structure
class WidgetContainer
     {
     Component[] myComponents;
     
     public void update()
          {
          if ( myComponents != null )
               for ( int k = 0; k < myComponents.length(); k++ )
                    myComponents[k].update();
          }
     public add( Component aComponent )
          {
          myComponents.append( aComponent );
          aComponent.setParent( this );
          }
     }
     
class Button extends Component
     {
     private Component parent;
     public void setParent( Component myParent)
          {
          parent = myParent;
          }
     
     etc.
     }

Doc 14 Composite and Decorator Slide # 7
More Issues

Should Component implement a list of Components?

The button etc. have a useless data member

Child Ordering is important in some cases

Who should delete components -

If there is no garbage collection Container is best bet



Applicability


Use Composite pattern when


Doc 14 Composite and Decorator Slide # 8

Java Use of Composite - AWT Widgets



Doc 14 Composite and Decorator Slide # 9
Specialized Java Containers


Doc 14 Composite and Decorator Slide # 10

Decorator

Problem - text views

A text view has the following features:

side scroll bar
bottom scroll bar
3D border
Flat border

This gives 12 different options:

TextView
TextViewWithNoBorder&SideScrollbar
TextViewWithNoBorder&BottomScrollbar
TextViewWithNoBorder&Bottom&SideScrollbar
TextViewWith3DBorder
TextViewWith3DBorder&SideScrollbar
TextViewWith3DBorder&BottomScrollbar
TextViewWith3DBorder&Bottom&SideScrollbar
TextViewWithFlatBorder
TextViewWithFlatBorder&SideScrollbar
TextViewWithFlatBorder&BottomScrollbar
TextViewWithFlatBorder&Bottom&SideScrollbar

How to implement?

Doc 14 Composite and Decorator Slide # 11

Solution 1 - Use Strategy


class TextView
     {
     Border myBorder;
     ScrollBar verticalBar;
     ScrollBar horizontalBar;
     
     public  void draw()
          {
          myBorder.draw();
          verticalBar.draw();
          horizontalBar.draw();
          code to draw self
          }
          
     etc.
     }

But TextView know about all the variations!
New type of variations require changing TextView
(and any other type of view we have)

Doc 14 Composite and Decorator Slide # 12

Solution 2 - Use Decorator

Turn the Strategy Inside out

TextView has no borders or scrollbars!
Add borders and scrollbars on top of a TextView

class TextView
     {
     public  void draw()
          {
          code to draw self
          }
          
     etc.
     }


Doc 14 Composite and Decorator Slide # 13
class FlatBorder
     {
     VisualComponent myComponent;
     
     public FlatBorder( VisualComponent aComponent )
          {
          myComponent = aComponent
          }
          
     public void draw()
          {
          int width = myComponent.width();
          int height = myComponent.height();
          
          myComponent.draw();
          code to draw FlatBorder
          }
     }
     
main()
     {
     TextView taxSummary = new TextView();
     VisualComponent flatTax = new FlatBorder( taxSummary );
     VisualComponent longTax = new VerticalScrollBar( flatTax );
     
     now use longTax
     }


Doc 14 Composite and Decorator Slide # 14

Applicability


Use Decorator:

to add responsibilities to individual objects dynamically and transparently

for responsibilities that can be withdrawn

when subclassing is impractical - may lead to too many subclasses

Consequences


More flexible than static inheritance

Avoids feature laden classes

Lots of little classes

A decorator and its components are not identical

so checking object identification can cause problems

Doc 14 Composite and Decorator Slide # 15

Implementation Issues


Keep Decorators lightweight

Don't put data members in VisualComponent




Doc 14 Composite and Decorator Slide # 16

Java Example of Decorator - Streams




import java.io.*;
import sdsu.io.*;
class  ReadingFileExample
     {
     public  static  void  main( String  args[]  ) throws Exception
          {
          FileInputStream inputFile;
          BufferedInputStream bufferedFile;
          ASCIIInputStream  cin;
          
          inputFile = new FileInputStream( "ReadingFileExample.java" );
          bufferedFile = new BufferedInputStream( inputFile );
          cin = new ASCIIInputStream( bufferedFile );

          System.out.println(  cin.readWord()  );

          for  ( int  k = 1 ;  k  <  4;  k++ )
               System.out.println(  cin.readLine()  );
          }
     }

----------