时间:2021-07-01 10:21:17 帮助过:32人阅读
/**
* 享元模式
*
* 运用享元技术有效的支持大量细粒度的对象
*/
class CD
{
private $_title = null;
private $_artist = null;
public function setTitle($title)
{
$this->_title = $title;
}
public function getTitle()
{
return $this->_title;
}
public function setArtist($artist)
{
$this->_artist = $artist;
}
public function getArtist($artist)
{
return $this->_artist;
}
}
class Artist
{
private $_name;
public function __construct($name)
{
echo "construct ".$name."
";
$this->_name = $name;
}
public function getName()
{
return $this->_name;
}
}
class ArtistFactory
{
private $_artists = array();
public function getArtist($name)
{
if(isset($this->_artists[$name]))
{
return $this->_artists[$name];
} else {
$objArtist = new Artist($name);
$this->_artists[$name] = $objArtist;
return $objArtist;
}
}
}
$objArtistFactory = new ArtistFactory();
$objCD1 = new CD();
$objCD1->setTitle("title1");
$objCD1->setArtist($objArtistFactory->getArtist('artist1'));
$objCD2 = new CD();
$objCD2->setTitle("title2");
$objCD2->setArtist($objArtistFactory->getArtist('artist2'));
$objCD3 = new CD();
$objCD3->setTitle("title3");
$objCD3->setArtist($objArtistFactory->getArtist('artist1'));
享元模式的精要有三点:
- 被系统大量使用的细粒度对象,粒度要有多细,量要有多大,看看jdk中使用的享元模式就知道了,jdk中,Integer,Character,String等都使用了享元模式,他们都是最基础的数据类型,不可谓不细,他们频繁的参与运算,不可谓不大量。
- 划分对象的内蕴属性/状态和外蕴属性/状态;所谓内蕴状态,就是存在对象的内部,不会随着环境变化的状态, 有一个网友说的很好,就是无区别的状态, 即拿掉外蕴属性之后同一类对象没有区别对象的内蕴状态就是对象的元神,只要元神元神无区别,那么对象也就无区别,同时也只有这些无区别的元神可以被共享,我想这也是Flyweight被翻译成享元的原因。外蕴状态就是由客户端指定,会随着环境变化的状态; 对于Integer来说, 他的内蕴属性其实就是他的value(当然它也没有外蕴属性);
- 用一个工厂控制享元的创造;因为享元对象不能被客户端随意创造, 否则就没有意义了。工厂通常提供缓存机制保存已经创造的享元。
面向对象虽然很好地解决了抽象性的问题,但是对于一个实际运行的软件系统,我们还需要考虑面向对象的代价问题,享元模式解决的就是面向对象的代价问题。享元模式采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。
享元模式在一般的项目开发中并不常用,而是常常应用于系统底层的开发,以便解决系统的性能问题。Java和.Net中的String类型就是使用了享元模式。如果在Java或者.NET中已经创建了一个字符串对象s1,那么下次再创建相同的字符串s2的时候,系统只是把s2的引用指向s1所引用的具体对象,这就实现了相同字符串在内存中的共享。如果每次执行s1=“abc”操作的时候,都创建一个新的字符串对象的话,那么内存的开销会很大。