极简设计模式-享元模式

PHP技术
369
0
0
2022-08-01

享元模式 - Flyweight Pattern

定义

运用共享技术有效地支持大量细粒度对象的复用。

系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。

享元概念

内部状态

在享元对象中可共享的状态叫内部状态。

外部状态

在享元对象中不可共享的状态叫外部状态。

享元池

享元工厂里面存在享元对象的变量叫做享元池。

设计的原则和思想

  1. 解耦的是享元对象中的内部状态和外部状态。
  2. 不变部分是内部状态,变化部分是外部状态。
  3. 核心思想是对象复用,节省内存。

一句话概括设计模式

共享对象。

结构中包含的角色

  1. Flyweight(抽象享元类)
  2. ConcreteFlyweight(具体享元类)
  3. UnsharedConcreteFlyweight(非共享具体享元类)
  4. FlyweightFactory(享元工厂类)

最小可表达代码

// 抽象享元类  
abstract class Flyweight {} 

// 具体享元类  
class ConcreteFlyweight extends Flyweight {}

// 非共享具体享元类
class UnsharedConcreteFlyweight extends Flyweight 
{
    private $flyweights = [];

    public function add($id, $flyweight)
    {
        $this->flyweights[$id] = $flyweight;
    }
}

// 享元工厂类
class FlyweightFactory 
{
    private static $flyweights = [];

    public static function getFlyweightById(int $id)
    {  
        if (empty(static::$flyweights[$id])) {
            var_dump("生成ID : {$id}");
            static::$flyweights[$id] = new ConcreteFlyweight();
        }

        return static::$flyweights[$id];
    }

    public static function getUnsharedConcreteFlyweightByIds(array $ids)
    {  
        $unsharedConcreteFlyweight = new UnsharedConcreteFlyweight(); 

        foreach ($ids as $id) {
            $unsharedConcreteFlyweight->add($id, self::getFlyweightById($id));
        }

        return $unsharedConcreteFlyweight;
    }  
}

$id = 1;
$ids = [1,2];
$flyweight = FlyweightFactory::getFlyweightById($id);
$unsharedConcreteFlyweight = FlyweightFactory::getUnsharedConcreteFlyweightByIds($ids);

优点

  1. 大大减少对象的创建,使效率提高。
  2. 节省内存,减少内存中对象的数量。
  3. 享元对象可以在不同的环境中被共享。

缺点

  1. 分离出内部状态和外部状态,使系统和代码都更加复杂。

何时使用

  1. 有大量相同或者相似的对象,造成内存的大量耗费。
  2. 需要多次重复使用享元对象时。
  3. 程序必须支持大量对象且没有足够的内存容量时。
  4. 需要缓冲池的场景。

实际应用场景

  1. JAVA 中的 String。
  2. 数据库的连接池。

享元模式 VS 对象池模式 VS 多例模式

享元模式

  1. 主要目的是节省空间。
  2. 在整个生命周期中,是被所有使用者共享的。
  3. 主要用于减少创建对象的数量,以减少内存占用和提高性能。
  4. 一个类可以创建多个对象,每个对象被多处代码引用共享。

对象池模式

  1. 主要目的是节省时间。
  2. 在任意时刻都不会被多处使用,而是被一个使用者独占,当使用完成之后,放回到池中,再由其他使用者重复利用。

多例模式

  1. 主要目的是为了限制对象的个数。