php设计模式之享元模式FlyWeight详细讲解

时间:2017-07-27
享元模式:池技术的重要实现方式, 运用共享技术有效的支持大量的细粒度对象,用于减少创建对象的数量,以减少内存占用和提高性能。本文章向大家详细介绍php享元模式FlyWeight。需要的朋友可以参考一下。

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

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

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

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

3,需要缓冲池的场景。
 

(二)享元模式的精要有三点:

  1. 被系统大量使用的细粒度对象,粒度要有多细,量要有多大,看看jdk中使用的享元模式就知道了,jdk中,Integer,Character,String等都使用了享元模式,他们都是最基础的数据类型,不可谓不细,他们频繁的参与运算,不可谓不大量。
  2. 划分对象的内蕴属性/状态和外蕴属性/状态;所谓内蕴状态,就是存在对象的内部,不会随着环境变化的状态, 有一个网友说的很好,就是无区别的状态, 即拿掉外蕴属性之后同一类对象没有区别对象的内蕴状态就是对象的元神,只要元神元神无区别,那么对象也就无区别,同时也只有这些无区别的元神可以被共享,我想这也是Flyweight被翻译成享元的原因。外蕴状态就是由客户端指定,会随着环境变化的状态; 对于Integer来说, 他的内蕴属性其实就是他的value(当然它也没有外蕴属性);
  3. 用一个工厂控制享元的创造;因为享元对象不能被客户端随意创造, 否则就没有意义了。工厂通常提供缓存机制保存已经创造的享元。

面向对象虽然很好地解决了抽象性的问题,但是对于一个实际运行的软件系统,我们还需要考虑面向对象的代价问题,享元模式解决的就是面向对象的代价问题。享元模式采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。

享元模式在一般的项目开发中并不常用,而是常常应用于系统底层的开发,以便解决系统的性能问题。Java和.Net中的String类型就是使用了享元模式。如果在Java或者.NET中已经创建了一个字符串对象s1,那么下次再创建相同的字符串s2的时候,系统只是把s2的引用指向s1所引用的具体对象,这就实现了相同字符串在内存中的共享。如果每次执行s1=“abc”操作的时候,都创建一个新的字符串对象的话,那么内存的开销会很大。

(三)享元模式代码实现:

//代码实现:
header("Content-type:text/html;Charset=utf-8");

//抽象享元角色
interface Flyweight{
     function show();
}
//共享的具体享元角色
class ConcreteFlyweight implements Flyweight{
    private $state;
    function __construct($state){
        $this->state = $state;
    }
    function show(){
        return $this->state;
    }
}
//不共享的具体享元角色,客户端直接调用
class UnsharedConcreteFlyweight implements Flyweight{
    private $state;
    function __construct($state){
        $this->state = $state;
    }
    function show(){
        return $this->state;
    }
}
//享元工厂模式
class FlyweightFactory{
    private $flyweights = array();
    function getFlyweight($state){
        if(!isset($this->flyweights[$state])){
            $this->flyweights[$state]=new ConcreteFlyweight($state);
        }
        return $this->flyweights[$state];
    }
}

//测试
$flyweightFactory = new FlyweightFactory();
$flyweightOne = $flyweightFactory->getFlyweight("state A");
echo $flyweightOne->show();
$flyweightTwo = new UnsharedConcreteFlyweight("state B");
echo $flyweightTwo->show();
/*
state A
state B
*/

(四)优缺点

优点

  • Flyweight模式可以大幅度地降低内存中对象的数量。

缺点

  • Flyweight模式使得系统更加复杂
  • Flyweigth模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长