PHP设计模式(十一)—享元模式 (Flyweight Pattern)

享元模式 (Flyweight Pattern): 池技术的重要实现方式, 运用共享技术有效的支持大量的细粒度对象,用于减少创建对象的数量,以减少内存占用和提高性能。

(一)为什么需要享元模式

1,在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

2,系统有大量相似对象。

3,需要缓冲池的场景。

(二)享元模式UML图

PHP设计模式(十一)—享元模式 (Flyweight Pattern)_第1张图片
Flyweight Pattern

(三)简单实例

这里引用《设计模式之禅》的例子,就是如果有一个报考信息系统,每个考生进来就实例化一个对象,传入他要报考的考点。由于考生分为30个考点,所以其实我们没有必要不停的实例化对象并释放,我们完全可以做一个缓冲池,若缓冲池中没有与这个考生相同考点的对象,则实例化一个,使用完不需要释放。下一个相同考点的考生进来后,只需复用这个对象。

address = $address;
    }
}
//具体享元角色  考生类
class ConcreteFlyweight extends Flyweight{
    //报考动作
    public function register(){
        echo "我的报考点是:{$this->address}".PHP_EOL;
    }
    //退出
    public function quit(){
        unset($this);
    }
}
//享元工厂 缓冲池
class FlyweightFactor{
    static private $students = array();
    static public function getStudent($address){
        $students =self::$students;
        //判断该键值是否存在
        if(array_key_exists($address,$students)){
            echo "缓冲池有考点为{$address},从池中直接取".PHP_EOL;   
        }else{
            echo "缓冲池没有,创建了考点为{$address}的对象并放到池中".PHP_EOL;
            self::$students[$address] = new ConcreteFlyweight($address);
        }
        return self::$students[$address];
    }
}

//实例化学生对象
$student_1 = FlyweightFactor::getStudent('广州');
//报考
$student_1 ->register();
// 退出
$student_1->quit();
//第二个学生进来
$student_2 = FlyweightFactor::getStudent('东莞');
//报考
$student_2 ->register();
// 退出
$student_2->quit();
//第三个学生进来
$student_3 = FlyweightFactor::getStudent('广州');
//报考
$student_3 ->register();
// 退出
$student_3->quit();

这里我们可以看到,当第三个学生进来时,由于和第一个学生的报考地点一致,所以只需从缓冲池取出。

ps:虽然ConcreteFlyweight的quit方法unset了$this,但是由于在FlyweightFactor中的students还存放着这个对象,所以unset只释放了变量$student_1,并没有完全删除这个对象,这就是student_3进来还能从缓冲池取得对象的原因

享元模式在PHP中可能比较少遇,但在Java中常常有这种情况。就是代码产生了大量的对象,虽然使用完有释放,但是由于垃圾回收需要一定时间,导致内存被耗尽。PHP经常应用web编程,脚本执行时间很短(30秒)。所以很少遇见这种情况,甚至我们使用完变量,连unset()函数都不用调用,就等着脚步执行结束后,自动释放。但是如果你试过在cli模式下运行PHP脚本,做一些socket通信,发送邮件等长耗时或是多连接任务时,就难免会遇到这种情况。

你可能感兴趣的:(PHP设计模式(十一)—享元模式 (Flyweight Pattern))