單例模式
所謂單例模式,就是確保某個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,即在應(yīng)用程序中只會(huì)有這個(gè)類的一個(gè)實(shí)例存在。
通常單例模式用在僅允許數(shù)據(jù)庫(kù)訪問(wèn)對(duì)象的實(shí)例中,從而防止打開(kāi)多個(gè)數(shù)據(jù)庫(kù)連接,單例模式是一種常見(jiàn)的設(shè)計(jì)模式,在計(jì)算機(jī)系統(tǒng)中,線程池、緩存、日志對(duì)象、對(duì)話框、打印機(jī)、數(shù)據(jù)庫(kù)操作、顯卡的驅(qū)動(dòng)程序常被設(shè)計(jì)成單例。
一個(gè)單例類應(yīng)包括以下幾點(diǎn):
和普通類不同,單例類不能被直接實(shí)例化,只能是由自身實(shí)例化。因此,要獲得這樣的限制效果,構(gòu)造函數(shù)必須標(biāo)記為private。
要讓單例類不被直接實(shí)例化而能起到作用,就必須為其提供這樣的一個(gè)實(shí)例。因此,就必須要讓單例類擁有一個(gè)能保存類的實(shí)例的私有靜態(tài)成員變量和對(duì)應(yīng)的一個(gè)能訪問(wèn)到實(shí)例的公共靜態(tài)方法。
在PHP中,為防止對(duì)單例類對(duì)象的克隆來(lái)打破單例類的上述實(shí)現(xiàn)形式,通常還為基提供一個(gè)空的私有__clone()方法。好吧,廢話不多說(shuō),概括如下
單例模式有以下3個(gè)特點(diǎn):
1.只能有一個(gè)實(shí)例,必須擁有一個(gè)構(gòu)造函數(shù),并且必須被標(biāo)記為private
2.必須自行創(chuàng)建這個(gè)實(shí)例,擁有一個(gè)保存類的實(shí)例的靜態(tài)成員變量
3.必須給其他對(duì)象提供這一實(shí)例,擁有一個(gè)訪問(wèn)這個(gè)實(shí)例的公共的靜態(tài)方法
單例類不能再其它類中直接實(shí)例化,只能被其自身實(shí)例化。它不會(huì)創(chuàng)建實(shí)例副本,而是會(huì)向單例類內(nèi)部存儲(chǔ)的實(shí)例返回一個(gè)引用
那么為什么要使用PHP單例模式?
PHP一個(gè)主要應(yīng)用場(chǎng)合就是應(yīng)用程序與數(shù)據(jù)庫(kù)打交道的場(chǎng)景,在一個(gè)應(yīng)用中會(huì)存在大量的數(shù)據(jù)庫(kù)操作,針對(duì)數(shù)據(jù)庫(kù)句柄連接數(shù)據(jù)庫(kù)的行為,使用單例模式可以避免大量的new操作。因?yàn)槊恳淮蝞ew操作都會(huì)消耗系統(tǒng)和內(nèi)存的資源。
單例模式恰恰是對(duì)全局變量的一種改進(jìn),避免那些存儲(chǔ)唯一實(shí)例的全局變量污染命名空間。你無(wú)法用錯(cuò)誤類型的數(shù)據(jù)覆寫一個(gè)單例。這種保護(hù)在不支持命名空間的PHP版本里尤其重要。因?yàn)樵赑HP中命名沖突會(huì)在編譯時(shí)被捕獲,并使腳本停止運(yùn)行。
下面是單例模式的代碼:
<?php
class Single {
private $name; // 聲明一個(gè)私有的實(shí)例變量
private function __construct(){
// 聲明私有構(gòu)造方法為了防止外部代碼使用new來(lái)創(chuàng)建對(duì)象。
}
static public $instance; // 聲明一個(gè)靜態(tài)變量(保存在類中唯一的一個(gè)實(shí)例)
static public function instance(){
// 聲明一個(gè)getinstance()靜態(tài)方法,用于檢測(cè)是否有實(shí)例對(duì)象
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::instance();
$ob = Single::instance();
$oa->setname('hello world');
$ob->setname('good morning');
echo $oa->getname(); //good morning
echo $ob->getname(); //good morning
單例模式的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
- 改進(jìn)系統(tǒng)的設(shè)計(jì)
- 是對(duì)全局變量的一種改進(jìn)
缺點(diǎn):
- 難于調(diào)試
- 隱藏的依賴關(guān)系
- 無(wú)法用錯(cuò)誤類型的數(shù)據(jù)覆寫一個(gè)單例
工廠模式
工廠模式就是一種類,是指包含一個(gè)專門用來(lái)創(chuàng)建其他對(duì)象的方法的類,工廠類在多態(tài)性編程實(shí)踐中是至關(guān)重要的,它允許動(dòng)態(tài)的替換類,修改配置,通常會(huì)使應(yīng)用程序更加靈活,熟練掌握工廠模式高級(jí)PHP開(kāi)發(fā)人員是很重要的。
工廠模式通常用來(lái)返回符合類似接口的不同的類,工廠的一種常見(jiàn)用法就是創(chuàng)建多態(tài)的提供者,從而允許我們基于應(yīng)用程序邏輯或者配置設(shè)置來(lái)決定應(yīng)實(shí)例化哪一個(gè)類,例如,可以使用這樣的提供者來(lái)擴(kuò)展一個(gè)類,而不需要重構(gòu)應(yīng)用程序的其他部分,從而使用新的擴(kuò)展后的名稱 。
通常,工廠模式有一個(gè)關(guān)鍵的構(gòu)造,根據(jù)一般原則命名為Factory的靜態(tài)方法,然而這只是一種原則,工廠方法可以任意命名,這個(gè)靜態(tài)還可以接受任意數(shù)據(jù)的參數(shù),必須返回一個(gè)對(duì)象。
具有為您創(chuàng)建對(duì)象的某些方法,這樣就可以使用工廠類創(chuàng)建對(duì)象,工廠模式在于可以根據(jù)輸入?yún)?shù)或者應(yīng)用程序配置的不同來(lái)創(chuàng)建一種專門用來(lái)實(shí)現(xiàn)化并返回其它類的實(shí)例的類,而不直接使用new,這樣如果想更改創(chuàng)建的對(duì)象類型,只需更改該工廠即可,
先舉個(gè)示例吧:
<?php
class Factory { // 創(chuàng)建一個(gè)基本的工廠類
static public function fac($id){ // 創(chuàng)建一個(gè)返回對(duì)象實(shí)例的靜態(tài)方法
if(1 == $id) return new A();
elseif(2==$id) return new B();
elseif(3==$id) return new C();
return new D();
}
}
interface FetchName { // 創(chuàng)建一個(gè)接口
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); // 調(diào)用工廠類中的方法
if($o instanceof FetchName){
echo $o->getname(); // DDDDD
}
$p=Factory::fac(3);
echo $p->getname(); // CCCCC
策略模式
策略模式是對(duì)象的行為模式,用意是對(duì)一組算法的封裝。動(dòng)態(tài)的選擇需要的算法并使用。
策略模式指的是程序中涉及決策控制的一種模式。策略模式功能非常強(qiáng)大,因?yàn)檫@個(gè)設(shè)計(jì)模式本身的核心思想就是面向?qū)ο缶幊痰亩嘈涡运枷搿?/p>
策略模式的三個(gè)角色:
1.抽象策略角色
2.具體策略角色
3.環(huán)境角色(對(duì)抽象策略角色的引用)
實(shí)現(xiàn)步驟:
1.定義抽象角色類(定義好各個(gè)實(shí)現(xiàn)的共同抽象方法)
2.定義具體策略類(具體實(shí)現(xiàn)父類的共同方法)
3.定義環(huán)境角色類(私有化申明抽象角色變量,重載構(gòu)造方法,執(zhí)行抽象方法)
就在編程領(lǐng)域之外,有許多例子是關(guān)于策略模式的。例如:
如果我需要在早晨從家里出發(fā)去上班,我可以有幾個(gè)策略考慮:我可以乘坐地鐵,乘坐公交車,走路或其它的途徑。每個(gè)策略可以得到相同的結(jié)果,但是使用了不同的資源。
策略模式的代碼實(shí)例:
<?php
abstract class baseAgent { //抽象策略類
abstract function PrintPage();
}
//用于客戶端是IE時(shí)調(diào)用的類(環(huán)境角色)
class ieAgent extends baseAgent {
function PrintPage() {
return 'IE';
}
}
//用于客戶端不是IE時(shí)調(diào)用的類(環(huán)境角色)
class otherAgent extends baseAgent {
function PrintPage() {
return 'not IE';
}
}
class Browser { //具體策略角色
public function call($object) {
return $object->PrintPage ();
}
}
$bro = new Browser ();
echo $bro->call ( new ieAgent () );
注冊(cè)模式
注冊(cè)模式,解決全局共享和交換對(duì)象。已經(jīng)創(chuàng)建好的對(duì)象,掛在到某個(gè)全局可以使用的數(shù)組上,在需要使用的時(shí)候,直接從該數(shù)組上獲取即可。將對(duì)象注冊(cè)到全局的樹(shù)上。任何地方直接去訪問(wèn)。
<?php
class Register
{
protected static $objects;
function set($alias, $object) // 將對(duì)象注冊(cè)到全局的樹(shù)上
{
self::$objects[$alias]=$object;//將對(duì)象放到樹(shù)上
}
static function get($name){
return self::$objects[$name];//獲取某個(gè)注冊(cè)到樹(shù)上的對(duì)象
}
function _unset($alias)
{
unset(self::$objects[$alias]);//移除某個(gè)注冊(cè)到樹(shù)上的對(duì)象。
}
}
適配器模式
將各種截然不同的函數(shù)接口封裝成統(tǒng)一的API。
PHP中的數(shù)據(jù)庫(kù)操作有MySQL,MySQLi,PDO三種,可以用適配器模式統(tǒng)一成一致,使不同的數(shù)據(jù)庫(kù)操作,統(tǒng)一成一樣的API。類似的場(chǎng)景還有cache適配器,可以將memcache,redis,file,apc等不同的緩存函數(shù),統(tǒng)一成一致。
首先定義一個(gè)接口(有幾個(gè)方法,以及相應(yīng)的參數(shù))。然后,有幾種不同的情況,就寫幾個(gè)類實(shí)現(xiàn)該接口。將完成相似功能的函數(shù),統(tǒng)一成一致的方法。
<?php
namespace IMooc;
interface IDatabase
{
function connect($host, $user, $passwd, $dbname);
function query($sql);
function close();
}
MYSQL
<?php
namespace IMooc\Database;
use IMooc\IDatabase;
class MySQL implements IDatabase
{
protected $conn;
function connect($host, $user, $passwd, $dbname)
{
$conn = mysql_connect($host, $user, $passwd);
mysql_select_db($dbname, $conn);
$this->conn = $conn;
}
function query($sql)
{
$res = mysql_query($sql, $this->conn);
return $res;
}
function close()
{
mysql_close($this->conn);
}
}
MYSQLI
<?php
namespace IMooc\Database;
use IMooc\IDatabase;
class MySQLi implements IDatabase
{
protected $conn;
function connect($host, $user, $passwd, $dbname)
{
$conn = mysqli_connect($host, $user, $passwd, $dbname);
$this->conn = $conn;
}
function query($sql)
{
return mysqli_query($this->conn, $sql);
}
function close()
{
mysqli_close($this->conn);
}
}
觀察者模式
1:觀察者模式(Observer),當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生變化時(shí),依賴它的對(duì)象全部會(huì)收到通知,并自動(dòng)更新。
2:場(chǎng)景:一個(gè)事件發(fā)生后,要執(zhí)行一連串更新操作。傳統(tǒng)的編程方式,就是在事件的代碼之后直接加入處理的邏輯。當(dāng)更新的邏輯增多之后,代碼會(huì)變得難以維護(hù)。這種方式是耦合的,侵入式的,增加新的邏輯需要修改事件的主體代碼。
3:觀察者模式實(shí)現(xiàn)了低耦合,非侵入式的通知與更新機(jī)制。
定義一個(gè)事件觸發(fā)抽象類。
EventGenerator.php
<?php
require_once 'Loader.php';
abstract class EventGenerator{
private $observers = array();
function addObserver(Observer $observer){
$this->observers[]=$observer;
}
function notify(){
foreach ($this->observers as $observer){
$observer->update();
}
}
}
定義一個(gè)觀察者接口 Observer.php
<?php
require_once 'Loader.php';
interface Observer{
function update();//這里就是在事件發(fā)生后要執(zhí)行的邏輯
}
//一個(gè)實(shí)現(xiàn)了EventGenerator抽象類的類,用于具體定義某個(gè)發(fā)生的事件
實(shí)現(xiàn):
require 'Loader.php';
class Event extends EventGenerator{
function triger(){
echo "Event<br>";
}
}
class Observer1 implements Observer{
function update(){
echo "邏輯1<br>";
}
}
class Observer2 implements Observer{
function update(){
echo "邏輯2<br>";
}
}
$event = new Event();
$event->addObserver(new Observer1());
$event->addObserver(new Observer2());
$event->triger();
$event->notify();