接上一次的《PHP实现树形结构》。由于菜单中的各种品类基本不变,跑同一次程序时候不会变化,所以只需在数据库查询一次,第一次初始化的时候查询好结果,以后每次取用即可直接返回。这里用php实现单例模式就能实现。
所谓单例模式是指整段程序中,类或者对象只会有一个实例的的设计模式。这种模式特别适合和数据库打交道的程序,比如上面所说的简历菜单树,因为只有一个实例,节省内资源,不用重复查询重复建立连接。
要实现单例模式,以下两点是重点:
1.他的构造函数必须声明为私有,否则其他地方可以随意new,失去了单例的意义。
2.由于外界不能new,所以内部要增加一个公共静态方法给外部取用这个实例。
另外,还可以注意一下以后的扩展。比如另外的树形结构也可以添加进来。
下面这段代码实现了菜单树的单例工厂模式,并且有一定的扩展性。文章最后会说明PHP单例模式的一些特点和不足。
/*
* 树的单例工厂模式
* @author zhengguorui
*/
class TreeFactory{
// 工厂类初始化标记
static public $instance;
//声明私有构造方法为了防止外部代码使用new来创建对象。
private function __construct(){}
// menu私有唯一实例
private $TreeOfMenu;
// menu的初始化方法
static private function initMenu(){
self::$instance->TreeOfMenu = new TreeMenu ( '目录导航' );
$tb = new IModel('category');
$list = $tb->query("visibility=1", "*", "parent_id, sort, id");
// 设置树形结构
for ($i = 0; $i < count($list); $i++) {
self::$instance->TreeOfMenu->setNode ( $list[$i]["id"], $list[$i]["parent_id"], $list[$i]["name"] );
}
//设置每个节点的品牌列表
$tb = new IModel('category_extend, brand, goods');
$list = $tb->query("shop_goods.id = shop_category_extend.goods_id and shop_brand.id = shop_goods.brand_id and shop_goods.is_del=0", "DISTINCT category_id, shop_goods.brand_id, shop_brand.name", "category_id, brand_id");
for ($i = 0; $i < count($list); $i++) {
self::$instance->TreeOfMenu->setBrand ( $list[$i]["category_id"], $list[$i]["brand_id"], $list[$i]["name"] );
}
}
// 工厂类和各种实例的初始化总入口
static public function getinstance($instType){
if(!self::$instance){
// 第一次则新建并初始化对象
self::$instance = new self();
}
// menu的初始化
if($instType=="menu"){
if(!self::$instance->TreeOfMenu){
self::initMenu();
}
// 返回menu实例
return self::$instance->TreeOfMenu;
}
return self::$instance;
}
}
虽然PHP单例模式可以优化一部分问题,但由于PHP是一种解释型的脚本语言,在吐回页面之后,程序就会消亡。这一点上,php和c以及java这类常驻型程序是不同的。所以PHP的单例模式仅仅是在一次程序的执行中单例,而不能跨用户跨页面实现单例。这也使得PHP的单例模式显得那么“山寨”,只适合用在单页面中触发大量查询请求的页面上。若需要长连接或者处理大量用户查询的网关,还是得由c来接手,这也不得不说是PHP语言上的一种遗憾吧!