PHP 单例模式和工厂模式
为什么要用单例模式?
php常常和数据库打交道,如果在应用中如果频繁建立连接对象,进行new操作的话,会消耗大料的系统内存资源,这并不是我们希望看到的。再则,在团队合作项目中,单例模式可以有效避免不同程序员new自己的对象,造成人为的系统消耗。
单例模式又称为职责模式,它用来在程序中创建一个单一功能的访问点,通俗地说就是实例化出来的对象是唯一的。
所有的单例模式至少拥有以下三种公共元素:
1. 它们必须拥有一个构造函数,并且必须被标记为private
2. 它们拥有一个保存类的实例的静态成员变量
3. 它们拥有一个访问这个实例的公共的静态方法
单例类不能再其它类中直接实例化,只能被其自身实例化。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。
-
class Single {
-
private $name;//声明一个私有的实例变量
-
private function __construct(){//声明私有构造方法为了防止外部代码使用new来创建对象。
-
-
}
-
-
static public $instance;//声明一个静态变量(保存在类中唯一的一个实例)
-
static public function getinstance(){//声明一个getinstance()静态方法,用于检测是否有实例对象
-
if(!self::$instance) self::$instance = new self();
-
return self::$instance;
-
}
-
-
public function setname($n){ $this->name = $n; }
-
public function getname(){ return $this->name; }
-
}
-
-
-
$oa = Single::getinstance();
-
$ob = Single::getinstance();
-
$oa->setname('hello world');
-
$ob->setname('good morning');
-
echo $oa->getname();//good morning
-
echo $ob->getname();//good morning
数据库中实现单例模式连接:
class Db{
private static $_instance;
private static $_dbConnect;
private $_config=array(
'host'=>'172.22.32.107',
'user'=>'itop',
'password'=>'itop',
'db'=>'test_zd_practice'
);
private function __construct()
{
}
private function __clone()
{
trigger_error('此类不可复制',E_CORE_ERROR);
}
public static function getInstance(){
if(!self::$_instance instanceof self){
self::$_instance=new self();
}
return self::$_instance;
}
public function connection(){
self::$_dbConnect=mysqli_connect($this->_config['host'],$this->_config['user'],$this->_config['password']);
if(!self::$_dbConnect){
throw new Exception("mysql connect error".mysql_error());
}
mysqli_set_charset(self::$_dbConnect,'utf8');
mysqli_select_db(self::$_dbConnect,$this->_config['db']);
return self::$_dbConnect;
}
}
$db=Db::getInstance();
try{
$conn= $db->connection();
$result=mysqli_query($conn,"select * from item");
var_dump($result);
}catch (Exception $e){
echo "数据库连接失败".$e->getMessage();
}
注意的知识点:this和self 的区别
1、意思上的区别:self代表类,$this代表对象(self是引用静态类的类名,而$this是引用非静态类的实例名)
2、用法上的区别:能用$this的地方一定使用self,能用self的地方不一定能用$this。
为什么要用工厂模式?
很多没接触过工厂模式的人会不禁问,为啥我要费那么大的劲儿去构造工厂类去创建对象呢?不去套用那些易维护,可扩展之类的话,我们可以考虑这样一个简单的问题。如果项目中,我们通过一个类创建对象。在快完成或者已经完成,要扩展功能的时候,发现原来的类类名不是很合适或者发现类需要添加构造函数参数才能实现功能扩展。我靠!我都通过这个类创建了一大堆对象实例了啊,难道我还要一个一个去改不成?我们现在才感受到了“高内聚低耦合”的博大精深。没问题,工厂方法可以解决这个问题。
再考虑一下,我要连接数据库,在php里面就有好几种方法,mysql扩展,mysqli扩展,PDO扩展。我就是想要一个对象用来以后的操作,具体要哪个,视情况而定喽。既然你们都是连接数据库的操作,你们就应该拥有相同的功能,建立连接,查询,断开连接...(此处显示接口的重要性)。总而言之,这几种方法应该“团结一致,一致对外”。如何实现呢?利用工厂模式。
工厂模式就是一种类,具有为您创建对象的某些方法,这样就可以使用工厂类创建对象,而不直接使用new。这样如果想更改创建的对象类型,只需更改该工厂即可。
-
class Factory {//创建一个基本的工厂类
-
static public function fac($id){//创建一个返回对象实例的静态方法
-
if(1 == $id) return new A();
-
elseif(2==$id) return new B();
-
elseif(3==$id) return new C();
-
return new D();
-
}
-
}
-
-
interface FetchName {//创建一个接口
-
public function getname();//
-
}
-
-
class A implements FetchName{
-
private $name = "AAAAA";
-
public function getname(){ return $this->name; }
-
}
-
-
class C implements FetchName{
-
private $name = "CCCCC";
-
public function getname(){ return $this->name; }
-
}
-
class B implements FetchName{
-
private $name = "BBBBB";
-
public function getname(){ return $this->name; }
-
}
-
-
class D implements FetchName{
-
private $name = "DDDDD";
-
public function getname(){ return $this->name; }
-
}
-
-
-
$o = Factory::fac(6);//调用工厂类中的方法
-
if($o instanceof FetchName){
-
echo $o->getname();//DDDDD
-
}
-
-
$p=Factory::fac(3);
-
echo $p->getname();//CCCCC