享元模式 - Flyweight Pattern
定义
运用共享技术有效地支持大量细粒度对象的复用。
系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。
享元概念
内部状态
在享元对象中可共享的状态叫内部状态。
外部状态
在享元对象中不可共享的状态叫外部状态。
享元池
享元工厂里面存在享元对象的变量叫做享元池。
设计的原则和思想
- 解耦的是享元对象中的内部状态和外部状态。
- 不变部分是内部状态,变化部分是外部状态。
- 核心思想是对象复用,节省内存。
一句话概括设计模式
共享对象。
结构中包含的角色
- Flyweight(抽象享元类)
- ConcreteFlyweight(具体享元类)
- UnsharedConcreteFlyweight(非共享具体享元类)
- 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);
优点
- 大大减少对象的创建,使效率提高。
- 节省内存,减少内存中对象的数量。
- 享元对象可以在不同的环境中被共享。
缺点
- 分离出内部状态和外部状态,使系统和代码都更加复杂。
何时使用
- 有大量相同或者相似的对象,造成内存的大量耗费。
- 需要多次重复使用享元对象时。
- 程序必须支持大量对象且没有足够的内存容量时。
- 需要缓冲池的场景。
实际应用场景
- JAVA 中的 String。
- 数据库的连接池。
享元模式 VS 对象池模式 VS 多例模式
享元模式
- 主要目的是节省空间。
- 在整个生命周期中,是被所有使用者共享的。
- 主要用于减少创建对象的数量,以减少内存占用和提高性能。
- 一个类可以创建多个对象,每个对象被多处代码引用共享。
对象池模式
- 主要目的是节省时间。
- 在任意时刻都不会被多处使用,而是被一个使用者独占,当使用完成之后,放回到池中,再由其他使用者重复利用。
多例模式
- 主要目的是为了限制对象的个数。