Flyweight Pattern

Purpose

To minimise memory usage, a Flyweight shares as much as possible memory with similar objects. It is needed when a large amount of objects is used that don't differ much in state. A common practice is to hold state in external data structures and pass them to the flyweight object when needed.

UML


Code

Text


namespace DesignPatterns\Structural\Flyweight;

/**
* This is the interface that all flyweights need to implement
*/ 
interface Text
{
  public function render(string $extrinsicState): string;
}

TextFactory


namespace DesignPatterns\Structural\Flyweight;

use Countable;

/**
* A factory manages shared flyweights. Clients should not instantiate them directly,
* but let the factory take care of returning existing objects or creating new ones.
*/
  class TextFactory implements Countable
  {
  /**
   * @var Text[]
   */
  private array $charPool = [];

  public function get(string $name): Text
  {
      if (!isset($this->charPool[$name])) {
          $this->charPool[$name] = $this->create($name);
      }

      return $this->charPool[$name];
  }

  private function create(string $name): Text
  {
      if (strlen($name) == 1) {
          return new Character($name);
      } else {
          return new Word($name);
      }
  }

  public function count(): int
  {
      return count($this->charPool);
  }
}

Word


namespace DesignPatterns\Structural\Flyweight;

class Word implements Text
{
    public function __construct(private string $name) { }

    public function render(string $extrinsicState): string
    {
        return sprintf('Word %s with font %s', $this->name, $extrinsicState);
    }
}

Character


namespace DesignPatterns\Structural\Flyweight;

/**
* Implements the flyweight interface and adds storage for intrinsic state, if any.
* Instances of concrete flyweights are shared by means of a factory.
*/
class Character implements Text
{
    /**
    * Any state stored by the concrete flyweight must be independent of its context.
    * For flyweights representing characters, this is usually the corresponding character code.
    */
    * 
    public function __construct(private string $name) { }

    public function render(string $extrinsicState): string
    {
         // Clients supply the context-dependent information that the flyweight needs to draw itself
         // For flyweights representing characters, extrinsic state usually contains e.g. the font
         return sprintf('Character %s with font %s', $this->name, $extrinsicState);
     }
}

In the code above, we create the flyweight classes via a Factory, then pass in the font at a later stage (when its needed). i.e


TextFactory::create('Stu')->render('TIMES_NEW_ROMAN');
// Outputs 'Word Stu with font TIMES_NEW_ROMAN'

TextFactory::create('S')->render('TIMES_NEW_ROMAN');
// Outputs 'Character S with font TIMES_NEW_ROMAN'

Ready to bring your vision to life?

We believe in excellence, empathy, integrity, and transparency throughout the process. Our goal is to build fast, responsive websites that not only perform but also reflect your values and vision.