二、结构型设计模式
7、享元模式(Flyweight Pattern)
这里是引用享元模式(Flyweight Pattern) 是一种结构型设计模式,旨在通过共享对象来减少内存使用,尤其适用于大量相似对象的场景。通过共享和重用对象的不可变部分(内部状态),从而减少重复对象的创建,节省内存。享元模式通过将对象的状态分为内部状态和外部状态,并共享内部状态,来优化内存使用。
享元模式的核心思想
享元模式的核心思想是共享对象,将多个对象的共同部分提取出来,避免内存中存在多个相同的实例对象。每个享元对象都包含
内部状态:对象本身的状态,是可以共享的
外部状态:与对象行为相关的状态,每个对象实例可能是不同的,无法共享。通过这种方式,多个相同的对象可以共享相同的内部状态,儿不同的外部状态通过外部喜传入。
享元模式的结构
享元模式通常由以下几个组成部分构成
1、Flyweight(享元接口):定义共享对象的接口,通常具有operation()方法,接受外部状态。
2、ConcreteFlyweight(具体享元):实现享元接口的具体类,通常会存储共享内部状态。
3、FlyweightFactory(享元工厂):负责创建和管理享元对象,确保对象的复用。当请求一个享元对象时,它会检查对象池中是否已有共享的对象,如果没有,就创建一个新的对象。
4、Client(客户端):负责给享元对象提供外部状态,并使用享元对象进行操作。
享元模式的工作流程
1、创建共享对象:当客户端请求一个对象时,享元工厂会检查是否已有相同的对象。如果有,就返回已存在的对象;如果没有,则创建新的对象。
2、共享内部状态:相同的享元对象共享内部状态,不同的对象实例通过外部状态来区分。
3、减少内存消耗:通过复用相同的对象,减少了不必要的对象创建,从而降低了内存消耗。
享元模式的代码实现
以下是一个使用享元模式的示例,假设我们有多个不同的字符对象,每个字符都有不同的外部状态(如位置、字体等),但字符的实际内容(如’A’、'B’等)是共享的内部状态。
1、定义享元接口和具体享元类
php">// 享元接口
interface Flyweight {public function operation($extrinsicState);
}// 具体享元类
class ConcreteFlyweight implements Flyweight {private $intrinsicState;public function __construct($intrinsicState) {$this->intrinsicState = $intrinsicState;}public function operation($extrinsicState) {// 操作内部状态与外部状态return "IntrinsicState: " . $this->intrinsicState . ", ExtrinsicState: " . $extrinsicState;}
}
2、享元工厂类
享元工厂类负责管理享元对象池,确保共享的对象不会重复创建。
php">在这里插入代码片class FlyweightFactory {private $flyweights = [];public function getFlyweight($key) {if (!isset($this->flyweights[$key])) {// 创建新的享元对象并缓存$this->flyweights[$key] = new ConcreteFlyweight($key);}return $this->flyweights[$key];}
}
3、客户端代码
客户端通过享元工厂获取共享对象,并传入外部状态来使用享元对象。
php">// 客户端代码
$factory = new FlyweightFactory();// 获取享元对象
$flyweight1 = $factory->getFlyweight("A");
$flyweight2 = $factory->getFlyweight("B");// 使用享元对象
echo $flyweight1->operation("Position: (10, 20), Font: Arial") . PHP_EOL;
// 输出: IntrinsicState: A, ExtrinsicState: Position: (10, 20), Font: Arialecho $flyweight2->operation("Position: (30, 40), Font: Times New Roman") . PHP_EOL;
// 输出: IntrinsicState: B, ExtrinsicState: Position: (30, 40), Font: Times New Roman
享元模式的优缺点
优点:
1、节省内存:通过共享对象,避免了重复创建相同的对象,从而节省内存。
2、提高性能:减少了内存的使用和对象创建的开销,提高了系统的性能。
3、灵活性和扩展性:通过外部状态的传入,客户端可以在不改变内部状态的情况下,动态地改变对象的行为。
缺点:
1、增加复杂度:需要将对象分为内部状态和外部状态,代码实现较为复杂。
2、难以管理:享元工厂类需要管理共享对象池,随着对象数量的增多,管理起来可能变得比较复杂。
3、外部状态的管理:在享元模式中,外部状态是传递给对象的,这可能需要额外的管理逻辑来确保对象的一致性。
适用场景
1、内存消耗大的系统:当需要创建大量相似对象时,使用享元模式可以显著减少内存使用。
2、对象状态可以分为内部和外部的情况:当对象的内部状态是可以共享的,而外部状态是可变的时,享元模式非常适用。
3、对象数量庞大且有相似性的场景:如文本编辑器中的字符对象、图形绘制中的图形对象等。
实际应用
1、文本编辑器:在文本编辑器中,字符是可以共享的,因为字符本身(如A、B)是固定的,然而每个字符的字体、大小、颜色等属性(外部状态)是不同的。
2、游戏开发:在大型多人在线游戏中,成千上万的玩家可能有相同的属性或行为,例如攻击动作、角色装备等,这些属性可以使用享元模式进行共享。