22、PHP 设计模式-享元模式

享元模式

享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。

模式结构

享元模式包含如下角色:

  • Flyweight: 抽象享元类
  • ConcreteFlyweight: 具体享元类
  • UnsharedConcreteFlyweight: 非共享具体享元类
  • FlyweightFactory: 享元工厂类

结构图

 

PHP代码实现


<?php

// 享元接口中声明了具体享元类的方法,这些方法可以接受外部状态。
interface Flyweight {
    public function operation($extrinsicState): void;
}

// 具体享元类包含了一个部分内在状态。这种状态的变量(例如,Character)必须是不可变的,因为享元的相同实例可能会在许多不同的上下文中同时使用。
class ConcreteFlyweight implements Flyweight {
    private $intrinsicState;

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

    public function operation($extrinsicState): void {
        echo "ConcreteFlyweight: Intrinsic State - " . $this->intrinsicState . ", Extrinsic State - " . $extrinsicState . ".\n";
    }
}

// 享元工厂决定是否复用已有的享元或创建一个新的对象。
class FlyweightFactory {
    private $flyweights = [];

    public function getFlyweight($key): Flyweight {
        if (!isset($this->flyweights[$key])) {
            $this->flyweights[$key] = new ConcreteFlyweight($key);
        }
        return $this->flyweights[$key];
    }

    public function listFlyweights(): void {
        $count = count($this->flyweights);
        echo "FlyweightFactory: I have $count flyweights:\n";
        foreach (array_keys($this->flyweights) as $key) {
            echo $key . "\n";
        }
    }
}

// 客户端代码通常会创建一大堆预先填充了不同上下文中享元对象的状态的享元。
$factory = new FlyweightFactory();

function addCarToPoliceDatabase(FlyweightFactory $ff, $plates, $owner, $brand, $model, $color) {
    echo "\nClient: Adding a car to database.\n";
    $flyweight = $ff->getFlyweight([$brand, $model, $color]);

    // 客户端代码以某种方式保存或计算外部状态(来自享元的状态)。
    $flyweight->operation([$plates, $owner]);
}

addCarToPoliceDatabase($factory, "CL234IR", "James Doe", "BMW", "M5", "red");
addCarToPoliceDatabase($factory, "CL234IR", "James Doe", "BMW", "X6", "red");

$factory->listFlyweights();