🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## **享元模式的定义与特点** **享元(Flyweight)模式定义:**: * 运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的又橡来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。 >[danger] 面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数。当对象数量太多时,将导致运行代价过高,带来性能下降等问题。享元模式正是为解决这一类问题而诞生的。享元模式通过共享技术实现相同或相似对象的重用。 **主要优点:** * 相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。 **其主要缺点是:** * 为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。 * 读取享元模式的外部状态会使得运行时间稍微变长。 ## **享元模式适用场景:** 享元模式是通过减少内存中对象的数量来节省内存空间的,所以以下几种情形适合采用享元模式。 * 一个应用程序使用了大量相同或相似的对象,这些对象耗费大量的内存资源,造成很大的存储开销 * 对象的大多数状态都可变为外部状态 * 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象 * 应用程序不依赖于对象标识 * 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。 * 由于享元模式需要额外维护一个保存享元的[数据结构](http://c.biancheng.net/data_structure/),所以应当在有足够多的享元实例时才值得使用享元模式。 ## **应用:** * String常量池 系统底层的设计。例如字符串的创建。如果两个字符串相同,则不会创建第二个字符串,而是第二个的引用直接指向第一个字符串。$str1=”abc”,$str2=”abc”.则内存存储中只会创建一个字符串“abc”而引用$str1.$str2都会指向它。 * 数据库连接池 ## **模式的结构** 享元模式的主要角色有如下。 1. 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。 2. 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。 3. 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。 4. 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。 ![](https://img.kancloud.cn/82/a6/82a68517d472c96c69aa71e1c2e96cf0_767x532.png) ``` //不共享的具体享元角色,客户端直接调用 class UnsharedConcreteFlyweight{ private $info; function __construct($info){ $this->info = $info; } function getInfo(){ return $this->info; } function setInfo($info){ $this->info=$info; } } //抽象享元角色 interface Flyweight{ function operation(UnsharedConcreteFlyweight $state); } //共享的具体享元角色1 class ConcreteFlyweight implements Flyweight{ private $key; function __construct(String $key){ $this->key = $key; echo "具体享元".$key."被创建!<br>"; } function operation(UnsharedConcreteFlyweight $outState){ echo "具体享元".$this->key."被调用!"; echo "非享元信息是:".$outState->getInfo()."<br>"; } } //享元工厂模式 class FlyweightFactory{ private $flyweights = array(); function getFlyweight($key){ if(!isset($this->flyweights[$key])){ $this->flyweights[$key]=new ConcreteFlyweight($key); } echo "具体享元".$state."已经存在,被成功获取!<br>"; return $this->flyweights[$key]; } } //测试 $flyweightFactory = new FlyweightFactory(); $flyweight1 = $flyweightFactory->getFlyweight("state A"); $flyweight2 = $flyweightFactory->getFlyweight("state A"); $flyweight3 = $flyweightFactory->getFlyweight("state A"); $flyweight4 = $flyweightFactory->getFlyweight("state B"); $unflyweight = new UnsharedConcreteFlyweight("C"); //非共享可以使是其他任何类对象 $flyweight1->operation($unflyweight); $flyweight2->operation($unflyweight); $flyweight3->operation($unflyweight); $flyweight4->operation($unflyweight); ``` **例子2:** ``` //所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。 abstract class Flyweight { //内部状态 string public $intrinsic; //外部状态 String protected $extrinsic; //这里要求享元角色必须接受外部状态 public function __construct($extrinsic) { $this->extrinsic = $extrinsic; } /** * 定义业务操作 * @param int $extrinsic 外部状态 */ public abstract function operate($extrinsic); /** * * @return String 获取外部状态 */ public function getIntrinsic() { return intrinsic; } /** * * @param String $intrinsic 设置外部状态 */ public function setIntrinsic($intrinsic) { $this->intrinsic = $intrinsic; } } //继承Flyweight超类或实现Flyweight接口,并为其内部状态增加存储空间 class ConcreteFlyweight extends Flyweight { /** * 实例化时就接受外部状态 * @param String $extrinsic [description] */ public function __construct($extrinsic) { parent::__construct($extrinsic); } /** * 根据外部状态进行逻辑处理 * @param int $extrinsic [description] * @return [type] [description] */ public function operate($extrinsic) { echo "具体Flyweight:".$extrinsic."<br>"; } } //指那些不需要共享的Flyweight子类。 class UnsharedConcreteFlyweight extends Flyweight { /** * * @param String $extrinsic [description] */ public function __construct($extrinsic) { parent::__construct($extrinsic); } /** * * @param int $extrinsic [description] * @return [type] [description] */ public function operate($extrinsic) { echo "不共享的具体Flyweight:" . $extrinsic ."<br>"; } } //享元工厂,用来创建并管理Flyweight对象 class FlyweightFactory { //定义一个池容器 private $pool =array(); //享元工厂 /** * / * @param String $extrinsic [description] * @return Flyweight [description] */ public function getFlyweight(String $extrinsic) { if(!isset($this->pool[$extrinsic])) { //池中没有该对象 //根据外部状态创建享元对象并放入池中 $this->pool[$extrinsic] = new ConcreteFlyweight($extrinsic); echo "创建 " . $extrinsic . " 并从池中取出----><br>"; }else{ echo "已有 " . $extrinsic . " 直接从池中取----><br>"; } return $this->pool[$extrinsic]; } } class Client { public static function main() { $extrinsic = 22; $FlyweightFactory= new FlyweightFactory(); $flyweightX = $FlyweightFactory->getFlyweight("X"); $flyweightX->operate(++$extrinsic); $flyweightY = $FlyweightFactory->getFlyweight("Y"); $flyweightY->operate(++$extrinsic); $flyweightZ = $FlyweightFactory->getFlyweight("Z"); $flyweightZ->operate(++$extrinsic); $flyweightReX = $FlyweightFactory->getFlyweight("X"); $flyweightReX->operate(++$extrinsic); //不共享的直接new 而不经过享元工厂 $unsharedFlyweight = new UnsharedConcreteFlyweight("X"); $unsharedFlyweight->operate(++$extrinsic); } } Client::main(); 结果: 创建 X 并从池中取出----> 具体Flyweight:23 创建 Y 并从池中取出----> 具体Flyweight:24 创建 Z 并从池中取出----> 具体Flyweight:25 已有 X 直接从池中取----> 具体Flyweight:26 不共享的具体Flyweight:27 ``` ## **享元模式的扩展** (1)**单纯享元模式**,这种享元模式中的所有的具体享元类都是可以共享的,不存在非共享的具体享元类,其结构图如图所示。 ![](https://img.kancloud.cn/41/0b/410b32f9c30cd180db6a8fdf10664900_513x496.png) (2) **复合享元模式**,这种享元模式中的有些享元对象是由一些单纯享元对象组合而成的,它们就是复合享元对象。虽然复合享元对象本身不能共享,但它们可以分解成单纯享元对象再被共享,其结构图如图所示 ![](https://img.kancloud.cn/f4/4c/f44c3008047178b4973127251e6f1c08_769x518.png)