Flyweight

Summary:  Use sharing to support large numbers of fine-grained objects efficiently.
Frequency of use:
Low

UML class diagram

Participants

The classes and 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 assets 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).

Structural 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.

     

using System;

using System.Collections;

 

namespace DoFactory.GangOfFour.Flyweight.Structural

{

  /// <summary>

  /// MainApp startup class for Structural

  /// Flyweight Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      // Arbitrary extrinsic state

      int extrinsicstate = 22;

 

      FlyweightFactory factory = new FlyweightFactory();

 

      // Work with different flyweight instances

      Flyweight fx = factory.GetFlyweight("X");

      fx.Operation(--extrinsicstate);

 

      Flyweight fy = factory.GetFlyweight("Y");

      fy.Operation(--extrinsicstate);

 

      Flyweight fz = factory.GetFlyweight("Z");

      fz.Operation(--extrinsicstate);

 

      UnsharedConcreteFlyweight fu = new

        UnsharedConcreteFlyweight();

 

      fu.Operation(--extrinsicstate);

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'FlyweightFactory' class

  /// </summary>

  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]);

    }

  }

 

  /// <summary>

  /// The 'Flyweight' abstract class

  /// </summary>

  abstract class Flyweight

  {

    public abstract void Operation(int extrinsicstate);

  }

 

  /// <summary>

  /// The 'ConcreteFlyweight' class

  /// </summary>

  class ConcreteFlyweight : Flyweight

  {

    public override void Operation(int extrinsicstate)

    {

      Console.WriteLine("ConcreteFlyweight: " + extrinsicstate);

    }

  }

 

  /// <summary>

  /// The 'UnsharedConcreteFlyweight' class

  /// </summary>

  class UnsharedConcreteFlyweight : Flyweight

  {

    public override void Operation(int extrinsicstate)

    {

      Console.WriteLine("UnsharedConcreteFlyweight: " +

        extrinsicstate);

    }

  }

}

Output
ConcreteFlyweight: 21
ConcreteFlyweight: 20
ConcreteFlyweight: 19
UnsharedConcreteFlyweight: 18

Real-world code in C#

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.

    

using System;

using System.Collections.Generic;

 

namespace DoFactory.GangOfFour.Flyweight.RealWorld

{

  /// <summary>

  /// MainApp startup class for Real-World

  /// Flyweight Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()

    {

      // Build a document with text

      string document = "AAZZBBZB";

      char[] chars = document.ToCharArray();

 

      CharacterFactory factory = new CharacterFactory();

 

      // extrinsic state

      int pointSize = 10;

 

      // For each character use a flyweight object

      foreach (char c in chars)

      {

        pointSize++;

        Character character = factory.GetCharacter(c);

        character.Display(pointSize);

      }

 

      // Wait for user

      Console.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'FlyweightFactory' class

  /// </summary>

  class CharacterFactory

  {

    private Dictionary<char, Character> _characters =

      new Dictionary<char, Character>();

 

    public Character GetCharacter(char key)

    {

      // Uses "lazy initialization"

      Character character = null;

      if (_characters.ContainsKey(key))

      {

        character = _characters[key];

      }

      else

      {

        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;

    }

  }

 

  /// <summary>

  /// The 'Flyweight' abstract class

  /// </summary>

  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);

  }

 

  /// <summary>

  /// A 'ConcreteFlyweight' class

  /// </summary>

  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 + ")");

    }

  }

 

  /// <summary>

  /// A 'ConcreteFlyweight' class

  /// </summary>

  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.

 

  /// <summary>

  /// A 'ConcreteFlyweight' class

  /// </summary>

  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)

.NET Optimized code in C#


The .NET optimized code demonstrates the same real-world situation as above but uses modern, built-in .NET features, such as, generics, reflection, LINQ, lambda functions, and more. You can find an example on our Singleton pattern page.

All other patterns, and so much more, are available in our Dofactory .NET product.


Dofactory .NET includes the Gang of Four and Enterprise patterns, but also many other innovations including our Ultra-Clean™ Architecture, powerful low-code tactics, Rapid Application Development (RAD) techniques, and much more.

Accelerate your application development to where you can write entire solutions in just 33 days!. This unique package will change your outlook on development and your career.  Here's what is included:






Dofactory .NET
.NET Developer Pack




Learn More



  • 69 gang-of-four pattern projects
  • 46 head-first pattern projects
  • Fowler's enterprise patterns
  • Multi-tier patterns
  • Convention over configuration
  • Active Record and CQRS patterns
  • Repository and Unit-of-Work patterns
  • MVC, MVP, & MVVM patterns
  • SparkTM Rapid App Dev (RAD) data access
  • Complete Analytics, Dashboard App
  • Complete Art Shop, Ecommerce App
  • Complete SaaS, Multi-Tenant App
  • Complete CRM, Customer Relationship App
  • 33-Day App Factory™
  • Everything 100% source code




Stay Inspired!
Join other developers and designers who have already signed up for our mailing list.
Terms     Privacy     Licensing       EULA       Sitemap      
© Data & Object Factory, LLC.
Made with    in Austin, Texas