实现方式
享元模式可能大家对定义什么的非常了解,但是今天我们先从实现开始逐步去分析;
interface Setting
{
public function init(int $userId);
}
class UserSetting implements Setting
{
private $userId;
public function init(int $userId) : self {
$this->userId = $userId;
return $this;
}
public function getPayMethod() : string {
return '获取'.$this->userId.'配置';
}
}
class SettingFactory
{
private static $settings = [];
// 获取配置
public function getSetting(int $userId)
{
if (! isset(self::$settings[$userId])) {
self::$settings[$userId] = (new UserSetting())->init($userId);
}
return self::$settings[$userId];
}
}
$settingFactory = new SettingFactory();
$userSetting = $settingFactory->getSetting(2);
echo $userSetting->getPayMethod();
// 输出的值为 “获取2配置”
具象的表达
首先定义一个配置初始化的接口(Setting),在创建用户配置类(UserSetting)实现这个接口的init方法,接着在创建一个SettingFactory工厂用于创建配置的享元模型。在工厂中我定义了一个静态变量(类型为数组),将userId作为key。UserSetting 类作为值存储。这样就完成了对用户配置对象的保存。
官方的定义
摒弃了在每个对象中保存所有数据的方式,通过共享多个对象所共同的相同状态,从而让我们能在有限的内存容量中载入更多的对象。前提是享元对象是不可变对象。
核心解决的问题就是节约空间,使用的办法是找出相似对象之间的共有特征,然后复用这些特征。享元模式要解决的问题是节约内存空间大小,而缓存模式本质上是为了节省时间。
使用享元模式的意义
- 减少内存消耗,节省服务器成本
- 聚合同一类的不可变对象,提高对象复用性。
何时使用
- 系统中有大量对象时
- 这些对象消耗大量内存时
- 这些对象的状态大部分可以外部化时。
优点
- 可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份
- 通过封装内存特有的运行状态,达到共享对象之间高效复用的目的。
缺点
- 以时间换空间,间接增加了系统的实现复杂度
- 运行时间更长,对于一些需要快速响应的系统并不合适。
总结
享元模式为共享对象定义了一个很好的结构范例,不过,用好享元模式的关键在于找到不可变对象。
课外扩展
Laravel中的IOC容器可以看作是一种享元模式的实现,它把对象保存在数组中,在需要的时候通过闭包机制进行取用,也有一些类共享一些状态属性的内容