备注:第四、五篇随《phper》第七期发布,杂志附件中含有文章中的代码
四、仅此一件--单件模式
1、变量的噩梦在重演
最早进行面向过程的开发的时候,我们常常会遇到一些变量,他在整个页面执行的时候,都是唯一的。
比如用户名,我们在页面的开始,如果取出了用户名,一般到页面结束,都是不变的。
我们希望减少数据库的查询,不必每次需要用到用户名的时候,反复查询。
最简单的办法,就是用一个全局的变量,来保存用户名,然后每次使用的时候调用,这样可以减少数据库的查询。
例:4_1
<?php
//用户名
$userName = 'lightsaber';
//显示用户名
function showUserInfo()
{
echo '用户名是'.$GLOBALS['userName'].'<br>';
}
//天气播报
function showWeather()
{
echo '向用户'.$GLOBALS['userName'].'播报天气<br>';
}
?>
这样出现了一个问题,就是需要共享的变量多了后,就难以控制和维护了,这个在以前的文章里讨论过了。
不过如果用了对象来保存的话,比如用一个用户类,里面的成员变量来保存,这又出现了一个问题:
我们每次new一个对象,不等于就是重新查询数据库吗?
如果我们用一个变量来引用对象,那么我们需要保存这个变量,不就是回到前面说的全局变量的情况了吗?
2、static的方案
既然我们知道我们要使用的是用户类,那么我们可以用静态static来保存数据
例:4_2
<?php
class userInfo
{
private static $userName;
//查询数据库,获得用户名
private static function findUserInfo()
{
//查询数据库,获得用户名
self::$userName = 'lightsaber';
}
public static function getUserInfo()
{
//判断是否已经获取了用户数据
if (self::$userName=='') self::findUserInfo();
return self::$userName;
}
}
//显示用户名
echo '用户名是'.userInfo::getUserInfo().'<br>';
//天气播报
echo '向用户'.userInfo::getUserInfo().'播报天气<br>';
?>
这样我们可以方便的通过用户类的静态方法,唯一的使用用户名这个数据。
3、对象的方案
static的设计,每次进行某个操作都要判断是否已经查询过数据。
如果用对象的方法就可以避免这一点,我们提供一个专门返回对象引用的方法getInstance,只有那个方法才有判断代码。
<?php
class userInfo
{
private $userName;
//唯一的实例
private static $instance;
//构造方法
private function __construct()
{
//查询数据库,获得用户名
$this->userName = 'lightsaber';
}
//获取对象实例
public static function getInstance()
{
if (self::$instance=='') self::$instance = new userInfo();
return self::$instance;
}
//返回用户信息
public function getUserInfo()
{
return $this->userName;
}
}
//获取唯一的实例
$userInfo = userInfo::getInstance();
//显示用户名
echo '用户名是'.$userInfo->getUserInfo().'<br>';
//天气播报
echo '向用户'.$userInfo->getUserInfo().'播报天气<br>';
?>
思考:
单件模式Singleton,在本文用了两种方式来实现,各有特点。
其实php应用最广泛的Singleton模式,可能就是数据库的唯一连接了。这时候我们可以将Singleton模式应用于PDO对象或者mysqli对象等。
而且Singleton用于数据库的时候,有一些问题:
1、此时只能操作一个数据库,对于两个以上的数据库,需要另行处理
2、如果仅仅以mysql_系列函数来处理mysql,默认就采用最近的一次连接,本身就带有单件的方式
3、php的生存期是页面级的,Singleton减少数据库连接的作用是有限的
同时因为以数据库为例的文章较多,而展现业务方面Singleton的应用比较少,本文希望提供Singleton更多的方面。