 |
Use sharing to support large numbers of fine-grained objects efficiently.
Frequency of use: low
|
|
 |
The classes and/or objects participating in this 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).
This structural code demonstrates the Flyweight pattern in which a relatively small
number of objects is shared many times by different clients.
Show code
|
// Flyweight pattern -- Structural example
|
|
using System;
using System.Collections;
namespace DoFactory.GangOfFour.Flyweight.Structural
{
// MainApp test application
class MainApp
{
static void Main()
{
// Arbitrary extrinsic 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 uf = new
UnsharedConcreteFlyweight();
uf.Operation(--extrinsicstate);
// Wait for user
Console.Read();
}
}
// "FlyweightFactory"
class FlyweightFactory
{
private Hashtable flyweights = new Hashtable();
// Constructor
public FlyweightFactory()
{
flyweights.Add("X", new ConcreteFlyweight());
flyweights.Add("Y", new ConcreteFlyweight());
flyweights.Add("Z", new ConcreteFlyweight());
}
public Flyweight GetFlyweight(string key)
{
return((Flyweight)flyweights[key]);
}
}
// "Flyweight"
abstract class Flyweight
{
public abstract void Operation(int extrinsicstate);
}
// "ConcreteFlyweight"
class ConcreteFlyweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.WriteLine("ConcreteFlyweight: " + extrinsicstate);
}
}
// "UnsharedConcreteFlyweight"
class UnsharedConcreteFlyweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.WriteLine("UnsharedConcreteFlyweight: " +
extrinsicstate);
}
}
}
|
Output
ConcreteFlyweight: 21
ConcreteFlyweight: 20
ConcreteFlyweight: 19
UnsharedConcreteFlyweight: 18
|
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.
Show code
|
// Flyweight pattern -- Real World example
|
|
using System;
using System.Collections;
namespace DoFactory.GangOfFour.Flyweight.RealWorld
{
// MainApp test application
class MainApp
{
static void Main()
{
// Build a document with text
string document = "AAZZBBZB";
char[] chars = document.ToCharArray();
CharacterFactory f = new CharacterFactory();
// extrinsic state
int pointSize = 10;
// For each character use a flyweight object
foreach (char c in chars)
{
pointSize++;
Character character = f.GetCharacter(c);
character.Display(pointSize);
}
// Wait for user
Console.Read();
}
}
// "FlyweightFactory"
class CharacterFactory
{
private Hashtable characters = new Hashtable();
public Character GetCharacter(char key)
{
// Uses "lazy initialization"
Character character = characters[key] as Character;
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
{
protected char symbol;
protected int width;
protected int height;
protected int ascent;
protected int descent;
protected int pointSize;
public abstract void Display(int pointSize);
}
// "ConcreteFlyweight"
class CharacterA : Character
{
// Constructor
public CharacterA()
{
this.symbol = 'A';
this.height = 100;
this.width = 120;
this.ascent = 70;
this.descent = 0;
}
public override void Display(int pointSize)
{
this.pointSize = pointSize;
Console.WriteLine(this.symbol +
" (pointsize " + this.pointSize + ")");
}
}
// "ConcreteFlyweight"
class CharacterB : Character
{
// Constructor
public CharacterB()
{
this.symbol = 'B';
this.height = 100;
this.width = 140;
this.ascent = 72;
this.descent = 0;
}
public override void Display(int pointSize)
{
this.pointSize = pointSize;
Console.WriteLine(this.symbol +
" (pointsize " + this.pointSize + ")");
}
}
// ... C, D, E, etc.
// "ConcreteFlyweight"
class CharacterZ : Character
{
// Constructor
public CharacterZ()
{
this.symbol = 'Z';
this.height = 100;
this.width = 100;
this.ascent = 68;
this.descent = 0;
}
public override void Display(int pointSize)
{
this.pointSize = pointSize;
Console.WriteLine(this.symbol +
" (pointsize " + this.pointSize + ")");
}
}
}
|
Output
A (pointsize 11)
A (pointsize 12)
Z (pointsize 13)
Z (pointsize 14)
B (pointsize 15)
B (pointsize 16)
Z (pointsize 17)
B (pointsize 18)
|
This .NET optimized code demonstrates the
same real-world situation as above but uses modern, built-in .NET features.
Show code
|
// Flyweight pattern -- .NET optimized
|
See our Singleton page for a .NET optimized code sample.
|
|
|