Definition
|
Use sharing to support large numbers of fine-grained objects efficiently. |
UML class diagram
Participants
|
The classes and/or objects participating in the Flyweight pattern are:
- Flyweight (Character)
- declares an interface through which flyweights can receive and act on extrinsic state.
- ConcreteFlyweight (CharacterA, CharacterB, ..., CharacterZ)
- implements the Flyweight interface and adds storage for intrinsic state, if any. A ConcreteFlyweight object must be sharable. Any state it stores must be intrinsic, that is, it must be independent of the ConcreteFlyweight object's context.
- UnsharedConcreteFlyweight ( not used )
- not all Flyweight subclasses need to be shared. The Flyweight interface enables sharing, but it doesn't enforce it. It is common for UnsharedConcreteFlyweight objects to have ConcreteFlyweight objects as children at some level in the flyweight object structure (as the Row and Column classes have).
- FlyweightFactory (CharacterFactory)
- creates and manages flyweight objects
- ensures that flyweight are shared properly. When a client requests a flyweight, the FlyweightFactory objects supplies an existing instance or creates one, if none exists.
- Client (FlyweightApp)
- maintains a reference to flyweight(s).
- computes or stores the extrinsic state of flyweight(s).
|
Sample code in C#
This structural code demonstrates the Flyweight pattern in which a relatively small number of objects is shared many times by different clients.
// Flyweight pattern -- Structural example |
using System;
using System.Collections;
// "FlyweightFactory"
class FlyweightFactory
{
// Fields
private Hashtable flyweights = new Hashtable();
// Constructors
public FlyweightFactory()
{
flyweights.Add("X", new ConcreteFlyweight());
flyweights.Add("Y", new ConcreteFlyweight());
flyweights.Add("Z", new ConcreteFlyweight());
}
// Methods
public Flyweight GetFlyweight(string key)
{
return((Flyweight)flyweights[ key ]);
}
}
// "Flyweight"
abstract class Flyweight
{
// Methods
abstract public void Operation( int extrinsicstate );
}
// "ConcreteFlyweight"
class ConcreteFlyweight : Flyweight
{
// Methods
override public void Operation( int extrinsicstate )
{
Console.WriteLine("ConcreteFlyweight: {0}",
extrinsicstate );
}
}
// "UnsharedConcreteFlyweight"
class UnsharedConcreteFlyweight : Flyweight
{
// Methods
override public void Operation( int extrinsicstate )
{
Console.WriteLine("UnsharedConcreteFlyweight: {0}",
extrinsicstate );
}
}
/// <summary>
/// Client test
/// </summary>
public class Client
{
public static void Main( string[] args )
{
// Arbitrary extrisic state
int extrinsicstate = 22;
FlyweightFactory f = new FlyweightFactory();
// Work with different flyweight instances
Flyweight fx = f.GetFlyweight("X");
fx.Operation( --extrinsicstate );
Flyweight fy = f.GetFlyweight("Y");
fy.Operation( --extrinsicstate );
Flyweight fz = f.GetFlyweight("Z");
fz.Operation( --extrinsicstate );
UnsharedConcreteFlyweight fu = new
UnsharedConcreteFlyweight();
fu.Operation( --extrinsicstate );
}
} |
This real-world code demonstrates the Flyweight pattern in which a relatively small number of Character objects is shared many times by a document that has potentially many characters.
// Flyweight pattern -- Real World example |
using System;
using System.Collections;
// "FlyweightFactory"
class CharacterFactory
{
// Fields
private Hashtable characters = new Hashtable();
// Methods
public Character GetCharacter( char key )
{
// Uses "lazy initialization"
Character character = (Character)characters[ key ];
if( character == null )
{
switch( key )
{
case 'A': character = new CharacterA(); break;
case 'B': character = new CharacterB(); break;
//...
case 'Z': character = new CharacterZ(); break;
}
characters.Add( key, character );
}
return character;
}
}
// "Flyweight"
abstract class Character
{
// Fields
protected char symbol;
protected int width;
protected int height;
protected int ascent;
protected int descent;
protected int pointSize;
// Methods
public abstract void Draw( int pointSize );
}
// "ConcreteFlyweight"
class CharacterA : Character
{
// Constructors
public CharacterA( )
{
this.symbol = 'A';
this.height = 100;
this.width = 120;
this.ascent = 70;
this.descent = 0;
}
// Methods
public override void Draw( int pointSize )
{
this.pointSize = pointSize;
Console.Write( this.symbol );
}
}
// "ConcreteFlyweight"
class CharacterB : Character
{
// Constructors
public CharacterB()
{
this.symbol = 'B';
this.height = 100;
this.width = 140;
this.ascent = 72;
this.descent = 0;
}
// Methods
public override void Draw( int pointSize )
{
this.pointSize = pointSize;
Console.Write( this.symbol );
}
}
// ... C, D, E, etc.
// "ConcreteFlyweight"
class CharacterZ : Character
{
// Constructors
public CharacterZ( )
{
this.symbol = 'Z';
this.height = 100;
this.width = 100;
this.ascent = 68;
this.descent = 0;
}
// Methods
public override void Draw( int pointSize )
{
this.pointSize = pointSize;
Console.Write( this.symbol );
}
}
/// <summary>
/// FlyweightApp test
/// </summary>
public class FlyweightApp
{
public static void Main( string[] args )
{
// Build a document with text
char[] document = {'A','B','Z','Z','A','A'};
CharacterFactory f = new CharacterFactory();
// extrinsic state
int pointSize = 12;
// For each character use a flyweight object
foreach( char c in document )
{
Character character = f.GetCharacter( c );
character.Draw( pointSize );
}
}
} |