Back Home Up Next


1 Purpose

2 Problem Description

3 Domain Definitions

4 Elisa Components

1  Purpose

Use sharing to support large numbers of fine-grained objects efficiently.


2  Problem Description

Some applications could benefit from using objects throughout their design, but a naive implementation would be prohibitively expensive.

For example, most document editor implementations have text formatting and editing facilities that are modularized to some extent. Object-oriented document editors typically use objects to represent embedded elements like tables and figures. However, they usually stop short of using an object for each character in the document, even though doing so would promote flexibility at the finest levels in the application. Characters and embedded elements could then be treated uniformly with respect to how they are drawn and formatted. The application could be extended to support new character sets without disturbing other functionality. The application's object structure could mimic the document's physical structure. The following diagram shows how a document editor can use objects to represent characters.

The drawback of such a design is its cost. Even moderate-sized documents may require hundreds of thousands of character objects, which will consume lots of memory and may incur unacceptable run-time overhead. The Flyweight pattern describes how to share objects to allow their use at fine granularities without prohibitive cost.

A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context—it's indistinguishable from an instance of the object that's not shared. Flyweights cannot make assumptions about the context in which they operate. The key concept here is the distinction between intrinsic and extrinsic state. Intrinsic state is stored in the flyweight; it consists of information that's independent of the flyweight's context, thereby making it sharable. Extrinsic state depends on and varies with the flyweight's context and therefore can't be shared. Client objects are responsible for passing extrinsic state to the flyweight when it needs it.

Flyweights model concepts or entities that are normally too plentiful to represent with objects. For example, a document editor can create a flyweight for each letter of the alphabet. Each flyweight stores a character code, but its coordinate position in the document and its typographic style can be determined from the text layout algorithms and formatting commands in effect wherever the character appears. The character code is intrinsic state, while the other information is extrinsic.

Logically there is an object for every occurrence of a given character in the document:

Physically, however, there is one shared flyweight object per character, and it appears in different contexts in the document structure. Each occurrence of a particular character object refers to the same instance in the shared pool of flyweight objects:

The class structure for these objects is shown next. Glyph is the abstract class for graphical objects, some of which may be flyweights. Operations that may depend on extrinsic state have it passed to them as a parameter. For example, Draw and Intersects must know which context the glyph is in before they can do their job.

A flyweight representing the letter "a" only stores the corresponding character code; it doesn't need to store its location or font. Clients supply the context-dependent information that the flyweight needs to draw itself. For example, a Row glyph knows where its children should draw themselves so that they are tiled horizontally. Thus it can pass each child its location in the draw request.

Because the number of different character objects is far less than the number of characters in the document, the total number of objects is substantially less than what a naive implementation would use. A document in which all characters appear in the same font and color will allocate on the order of 100 character objects (roughly the size of the ASCII character set) regardless of the document's length. And since most documents use no more than 10 different font-color combinations, this number won't grow appreciably in practice. An object abstraction thus becomes practical for individual characters.

3  Domain Definitions

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

Glyph = Row | Character | Column

The next step is to translate the domain definition into a number of Elisa components. In addition, we will use skeletons of definitions derived from the preceding diagrams.

4  Elisa components 

Based on the domain definitions a set of related components are derived. The first component implements  a skeleton of the

component Glyphs;
type Glyph = category(Row, Character, Column);

     Draw(Glyph, Context) -> nothing;

     Intersects(Glyph, Point, Context) -> boolean; 
        . . .

            <<implementations of >>

     Draw(Row:row, context) = Draw(row, context); 

     Draw(Character:char, context) = Draw(char, context); 

     Draw(Column:column, context) = Draw(column, context); 


     Intersects(Row:row, point, context) = Intersects(row, point, context);

end component Glyphs;

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


component Rows;
type Row;

     CreateRow(Context) -> Row;
     Draw(Row, Context) -> nothing;

     Intersects(Row, Point, Context) -> boolean; 
        . . .

            <<implementations of >>
     CreateRow(context) = Row:[...];

     Draw(row, context) = ...; 

     Intersects(row, point, context) = ...;
        . . .

end component Rows;


The following component is a skeleton example of a Character


component Characters;
type Character;

     CreateCharacter(Context) -> Character;
     Draw(Character, Context) -> nothing;

     Intersects(Character, Point, Context) -> boolean; 
        . . .

            <<implementations of >>
     CreateCharacter(context) = Character:[...];

     Draw(char, context) = ...; 

     Intersects(char, point, context) = ...;
        . . .

end component Characters;


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


component Columns;
type Column;

     CreateColumn(Context) -> Column;
     Draw(Column, Context) -> nothing;

     Intersects(Column, Point, Context) -> boolean; 
        . . .

            <<implementations of >>
     CreateColumn(context) = Column:[...];

     Draw(column, context) = ...; 

     Intersects(column, point, context) = ...;
        . . .

end component Columns;

Back Home Up Next

  Part 5: Design Patterns   Flyweight


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 27-11-2012 16:58:29   

free hit counter