不断学习不断进步的过程中,坚持用写作的方式记录学习成果真真是极好的习惯。最近笔者学习设计模式,正好有写博客的想法,于是第一篇博客就从设计模式中的一小个——单例模式讲起。
此文于php实现单例模式又略有些拓展,将使用单例模式的设计手法实现一个多例模式。应用场景如下:
因我公司的用户注册后每一个用户拥有一个独享的私人库,于是我们在代码实现的过程中会出来一个进程连接多个数据库的情况。然而对于数据库连接来说,一个进程中一个数据库连接一次关闭一次是再好不过的,于是使用单例模式实在是情理之中的事。两者结合,便有了以下内容。看官且莫嫌烦,搞清需求再代码实现真真是你们序员不可避免的正确的路子。
弄清楚需求后,我们就开始代码实现了:
<?php
class MysqlConn{
/*根据我们的需求,我们要连接不同的数据库,但是会有一个常用的数据库连接,因此定义几个常量作为连接数据库的缺省值*/
const HOSTNAME = "localhost";
const USERNAME = "root";
const PASSWORD = "password";
const DBNAME = "mysql";
const CHARSET = "utf8";
/*单例的精要所在便是一个类在一个进程只只生成一个对象,对于本类我们需要的只是数据库的连接句柄*/
/*instances 之所以为 static 是因为我们要用它来保存本类的唯一对象,于是需要在实例化对象之前对其是否存在进行判断*/
/*instances 之所以为 数组,是因为我们说过我们需要连接不同的数据库,实际上这不是一个严格的单例模式,是一个多例模式*/
private static $instances = array(); //静态属性,实现一个单例
private $db; //返回一个数据库连接句柄
/* key 用来确实我们的唯一对象,一个 $instances[$key] 即为一个单例 */
private $key;
/*构造函数连接数据库并获得句柄, private 禁止在类外实例化对象*/
private function __construct($hostname, $username, $password, $dbname){
try{
$this -> db = new mysqli($hostname, $username, $password, $dbname);
$this -> db -> set_charset(self::CHARSET);
/* 使用数据库名字来作为确定一个单例,如果要连接不同域下的数据库,使用“域名”和“数据库”共同hash作为key值*/
$this -> key = $dbname;
if(mysqli_connect_errno()){
throw new Exception("数据库连接失败");
}
}catch(Exception $e){
$e -> getMessage();
}
}//end construct
/*以下三个 private 的方法都是为了禁止类外的调用,保证单例 */
/*禁止外部克隆对象*/
private function __clone(){}
/*禁止外部序列化对象*/
private function __sleep(){}
/*禁止外部反序列化对象*/
private function __wakeup(){}
/*获取一个单例,并指定参数缺省值,如果需要连接其他数据库,传入参数即可,否则参数可空*/
public static function getInstance($hostname = self::HOSTNAME, $username = self::USERNAME, $password = self::PASSWORD, $dbname = self::DBNAME){
if(!isset(self::$instances[$dbname])){
self::$instances[$dbname] = new self($hostname, $username, $password, $dbname);
var_dump(self::$instances[$dbname]);
}
return self::$instances[$dbname];
}//end getInstance
/*返回数据库连接句柄,因为我们之前的 this -> db 私有化,所以此所需要一个公开方法来返回*/
public function getDb(){
return $this -> db;
}
public function __destruct(){
$this -> db -> close();self::$instances[$this->key] = NULL;
}}
外部调用代码,如下:
<?php
require "MysqlConn.php";
/*如果需要连接其他库,传入参数即可*/
$conn = MysqlConn::getInstance();
$db = $conn -> getDb();
最后,鄙人首次触及技术博客,也不知是否讲得清楚,欢迎众高人批证与加入讨论。在此特感谢与我一起研究单例模式的一哥(一哥现在还是小神,但是他有一天会是大神,因为其一直以大神的标准严格要求自己)和授于我们设计模式的大师兄。在此推荐一哥博客:http://my.csdn.net/zinss26914