為了最大限度地減少內(nèi)存使用,享元與相似對(duì)象共享盡可能多的內(nèi)存。當(dāng)使用大量狀態(tài)差異不大的對(duì)象時(shí)需要它。一種常見(jiàn)的做法是將狀態(tài)保存在外部數(shù)據(jù)結(jié)構(gòu)中,并在需要時(shí)將它們傳遞給享元對(duì)象。
Text.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Flyweight; /** * This is the interface that all flyweights need to implement */ interface Text { public function render(string $extrinsicState): string; }
Word.php
<?php 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.php
<?php declare(strict_types=1); 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); } }
TextFactory.php
<?php declare(strict_types=1); 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); } }
Tests/FlyweightTest.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Flyweight\Tests; use DesignPatterns\Structural\Flyweight\TextFactory; use PHPUnit\Framework\TestCase; class FlyweightTest extends TestCase { private array $characters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; private array $fonts = ['Arial', 'Times New Roman', 'Verdana', 'Helvetica']; public function testFlyweight() { $factory = new TextFactory(); for ($i = 0; $i <= 10; $i++) { foreach ($this->characters as $char) { foreach ($this->fonts as $font) { $flyweight = $factory->get($char); $rendered = $flyweight->render($font); $this->assertSame(sprintf('Character %s with font %s', $char, $font), $rendered); } } } foreach ($this->fonts as $word) { $flyweight = $factory->get($word); $rendered = $flyweight->render('foobar'); $this->assertSame(sprintf('Word %s with font foobar', $word), $rendered); } // Flyweight pattern ensures that instances are shared // instead of having hundreds of thousands of individual objects // there must be one instance for every char that has been reused for displaying in different fonts $this->assertCount(count($this->characters) + count($this->fonts), $factory); } }
更多建議: