享元模式【Flyweight】

实例

abstract class WebSite
{
    protected $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public abstract function use(User $user);
}

class ConcreteWebSite extends WebSite
{
    public function use(User $user)
    {
        echo '分类:', $this->name, PHP_EOL;
        echo '用户:', $user->getName(), PHP_EOL;
    }
}

class WebSiteFactory
{
    private $flyweight = [];

    public function getWebSiteCategory($key)
    {
        if (empty($this->flyweight[$key])) {
            $this->flyweight[$key] = new ConcreteWebSite($key);
        }

        return $this->flyweight[$key];
    }

    public function getWebSiteCount()
    {
        echo '分类总数:', count($this->flyweight), PHP_EOL;
    }
}

class User
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }
}

$webSiteFactory = new WebSiteFactory();

$videoSite = $webSiteFactory->getWebSiteCategory('video');
$videoSite->use(new User('小红'));

$liveSite = $webSiteFactory->getWebSiteCategory('live');
$liveSite->use(new User('小明'));

$liveSite = $webSiteFactory->getWebSiteCategory('video');
$liveSite->use(new User('小牛'));

$liveSite = $webSiteFactory->getWebSiteCategory('live');
$liveSite->use(new User('小黄'));

$webSiteFactory->getWebSiteCount();
/*
分类:video
用户:小红
分类:live
用户:小明
分类:video
用户:小牛
分类:live
用户:小黄
分类总数:2
*/

总结

享元模式通过工厂集中控制,将对象的共享部分(内部状态)抽象出来并复用,将变化部分(外部状态)作为参数传入,以极少的对象实例高效地管理海量细粒度对象。

意图

运用共享技术,高效支持大量细粒度的对象

主要解决

避免创建大量相似对象导致的内存溢出和存储开销。

何时使用

  1. 系统中有大量对象。
  2. 这些对象消耗大量内存。
  3. 这些对象的状态大部分可以外部化。
  4. 这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
  5. 系统不依赖于这些对象身份,这些对象是不可分辨的。

如何解决

关键代码

用 HashMap 存储这些对象。

优点

大幅减少对象创建,显著降低系统内存占用,提高效率。

缺点

提高了系统复杂性,必须准确划分内部与外部状态,且需警惕线程安全问题。

使用场景

注意事项

  1. 注意划分外部状态和内部状态,否则可能会引起线程安全问题。
  2. 这些类必须有一个工厂对象加以控制。