Purpose
The purpose of the design pattern
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
UML design pattern diagram
Code
Code snippets
Text
Interface that all flyweight objects must implement.
namespace DesignPatterns\Structural\Flyweight;
/**
* This is the interface that all flyweights need to implement
*/
interface Text
{
public function render(string $extrinsicState): string;
}
TextFactory
This factory manages shared flyweights. The factory takes care of instanitating the flyweight objects.
In this example we either create a new Word or Character object based on the length of the string passed into the Factory create method, i.e TextFactory::create('stu') would create and return a Word class.
In this example we either create a new Word or Character object based on the length of the string passed into the Factory create method, i.e TextFactory::create('stu') would create and return a Word class.
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
Note - this uses PHP 8 constructor property promotion.
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
Note - this uses PHP 8 constructor property promotion.
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'