談從魔獸看PHP設(shè)計(jì)模式_PHP教程
前段時(shí)間看到有人用魔獸來(lái)解釋設(shè)計(jì)模式,感覺很有意思,于是我把它改了改,又添加了些設(shè)計(jì)模式內(nèi)容,今天發(fā)出來(lái)。有些地方借鑒了前人的內(nèi)容,沒有注明,請(qǐng)前人不要見怪啊。
這里用大家感興趣的魔獸3來(lái)討論P(yáng)HP的幾種常見的設(shè)計(jì)模式:?jiǎn)渭J健⒉呗阅J健⒐S模式、觀察者模式。今天就講這四個(gè)吧,以后繼續(xù)。
這些設(shè)計(jì)模式,都是針對(duì)面向?qū)ο髞?lái)說(shuō)的,所以都用PHP5,另外在這里我想說(shuō)的是PHP4從2008年8月8日(我記得是和北京奧運(yùn)會(huì)同一天,沒查證,呵呵)的時(shí)候官方就發(fā)了最后一個(gè)PHP4的補(bǔ)丁,這意味這PHP4的時(shí)代已經(jīng)終結(jié),所以,我建議大家現(xiàn)在就別理PHP4吧,就以PHP5來(lái)說(shuō)吧。
一、單件模式:
問題的提出:
某些應(yīng)用程序資源是獨(dú)占的,因?yàn)橛星抑挥幸粋(gè)此類型的資源。例如,通過數(shù)據(jù)庫(kù)句柄到數(shù)據(jù)庫(kù)的連接是獨(dú)占的。您希望在應(yīng)用程序中共享數(shù)據(jù)庫(kù)句柄,因?yàn)樵诒3诌B接打開或關(guān)閉時(shí),它是一種開銷,在獲取單個(gè)頁(yè)面的過程中更是如此。
問題的解決:
那么下面我們就開始玩魔獸吧。首先雙擊war3.exe,這時(shí)候就開始運(yùn)行魔獸了。我們用代碼來(lái)實(shí)現(xiàn)吧。
<?php
class War3
{
public function __construct()
{
echo "War3 is Running.","<br />";
}
}
$war = new War3();
運(yùn)行!很好,輸出
War3 is Running.
我們已經(jīng)可以開始游戲了,但是,如果我在代碼末尾再加入
$war2 = new War3();
$war3 = new War3();
會(huì)怎么樣呢?我們?cè)囋,輸出結(jié)果:
War3 is Running.
War3 is Running.
War3 is Running.
完了,如果不小心雙擊了兩次就開了3個(gè)魔獸,那如果再雙擊幾次,那電腦肯定爆掉。。。我們還是來(lái)想想解決方法吧。
既然我們不能這么隨意的就把這個(gè)類實(shí)例化了,那么我們就把構(gòu)造函數(shù)改成私有方法。
class War3
{
private function __construct()
{
echo "War3 is Running.","<br />";
}
}
可是私有變量外部是無(wú)法訪問的,這樣以來(lái),我們就連一個(gè)都打不開了啊。別急,我們?cè)俳o他加一個(gè)不用通過實(shí)例化,外部也能訪問的函數(shù),那就是靜態(tài)函數(shù),
class War3
{
private function __construct()
{
echo "War3 is Running.","<br />";
}
public static function runWar()
{
}
}
通過這個(gè)靜態(tài)的方法runWar()我們來(lái)控制類War3的實(shí)例化,那么還缺上一個(gè)標(biāo)識(shí),我們?cè)賱?chuàng)建一個(gè)標(biāo)識(shí),通過這個(gè)標(biāo)識(shí)來(lái)表示我們的類是否已經(jīng)實(shí)例化,如果實(shí)例化,直接返回句柄就行了。
把類修改成
class War3
{
protected static $_instance = null;
private function __construct()
{
echo "War3 is Running.","<br />";
}
public static function runWar()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
當(dāng)然,我們運(yùn)行魔獸時(shí)的實(shí)例化也要換種方法,就通過
$war = War3::runWar();
就能開始玩魔獸了,好了,下面把完整的代碼附上來(lái):
<?php
class War3
{
protected static $_instance = null;
private function __construct()
{
echo "War3 is Running.","<br />";
}
public static function runWar()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
$war = War3::runWar();
$war2 = War3::runWar();
$war3 = War3::runWar();
運(yùn)行一下,結(jié)果是:
War3 is Running.
太好了,我雙擊了這么多次,也就只運(yùn)行了一個(gè)魔獸,現(xiàn)在隨便你怎么打開,機(jī)子都不會(huì)爆掉了。
這就是傳說(shuō)中的單價(jià)模式,主要用于一些很占資源的而且實(shí)例僅有一個(gè)實(shí)例就夠用的東西,比如,zend framework中的Zend_Controller_Front前端控制器,就是采用單價(jià)模式來(lái)設(shè)計(jì)的,大家有興趣的話可以看看那個(gè)。
二、策略模式:
問題的提出:
在此模式中,算法是從復(fù)雜類提取的,因而可以方便地替換。例如,如果要更改搜索引擎中排列頁(yè)的方法,則策略模式是一個(gè)不錯(cuò)的選擇。思考一下搜索引擎的幾個(gè)部分 —— 一部分遍歷頁(yè)面,一部分對(duì)每頁(yè)排列,另一部分基于排列的結(jié)果排序。在復(fù)雜的示例中,這些部分都在同一個(gè)類中。通過使用策略模式,您可將排列部分放入另一個(gè)類中,以便更改頁(yè)排列的方式,而不影響搜索引擎的其余代碼。
問題的解決:
呵呵,不講那么復(fù)雜,剛才魔獸好不容易打開了,我們還是玩魔獸好了。
下面我們選battle,哇好多種族啊,有人族(Human),獸族(ORC),暗夜精靈族(Nighy Elf),不死族(Undead)。我選精靈族(Nighy Elf),再選一個(gè)精靈族和兩個(gè)獸族(ORC),一個(gè)獸族和我是一家的,另一個(gè)精靈族和獸族是另一家的。
每一個(gè)玩家在進(jìn)入游戲后都會(huì)得到一些資源,如一個(gè)大廳,五個(gè)小精靈(苦工)和一個(gè)礦山。這些可以稱為是初始化的一些東西,這里我們就可以用到策略模式來(lái)封裝這些初始化。
進(jìn)入正題,首先我們來(lái)構(gòu)建一個(gè)玩家類:
<?php
class player
{
//玩家名字
protected $_name;
//種族
protected $_race;
//隊(duì)伍
protected $army;
//建筑
protected $building;
//人口
protected $population;
//黃金
protected $gold;
//木材
protected $wood;
//構(gòu)造函數(shù),設(shè)定所屬種族
public function __construct($race)
{
$this->race = $race;
}
//__get()方法用來(lái)獲取保護(hù)屬性
private function __get($property_name)
{
if(isset($this->$property_name)) {
return($this->$property_name);
}
else {
return(NULL);
}
}
//__set()方法用來(lái)設(shè)置保護(hù)屬性
private function__set($property_name,$value)
{
$this->$property_name=$value;
}
}
接著,我們?cè)俳ㄒ粋(gè)玩家初始化的接口,
<?php
interface initialPlayer
{
//制造初始化的部隊(duì)
public function giveArmy($player);
//制造初始化的建筑
public function giveBuilding($player);
//初始化資源
public function giveSource($player);
}
好了,到這里我們就該對(duì)這個(gè)接口來(lái)實(shí)現(xiàn)了,為了方便,我只選了兩個(gè)種族,就只寫這兩個(gè)種族的初始化了:
首先是精靈族:
<?php
class NighyElfInitial implements initialPlayer
{
//制造初始化的部隊(duì)
public function giveArmy($player)
{
//五個(gè)小精靈
for($i=0; $i<=5;$i++)
{
$creator = new CreatArms();//這個(gè)是創(chuàng)建部隊(duì)類,在后面得工廠模式中會(huì)用到,這里我就不多說(shuō)了
$player->army[] = $creator->Creat('Wisp','./Arms/');
}
}
//制造初始化的建筑
public function giveBuilding($player)
{
$creator = new CreatBuildings();
//一個(gè)基地
$player->building[] = $creator->Creat('TownHall','./Buildings/');
//一個(gè)礦場(chǎng)
$player->building[] = $creator->Creat('Mine','./Buildings/');
}
//初始化人口上限
public function giveSource($player)
{
$player->population= 10;
$player->gold= 1000;
$player->wood= 100;
}
}
接下來(lái)是獸族:
<?php
class ORCInitial implements initialPlayer
{
//制造初始化的部隊(duì)
public function giveArmy($player)
{
//五個(gè)苦工
for($i=0; $i<=5;$i++)
{
$creator = new CreatArms();//這個(gè)是創(chuàng)建部隊(duì)類,在后面得工廠模式中會(huì)用到,這里我就不多說(shuō)了
$player->army[] = $creator->Creat('Peon','./Arms/');
}
}
//制造初始化的建筑
public function giveBuilding($player)
{
$creator = new CreatBuildings();
//一個(gè)基地
$player->building[] = $creator->Creat('TownHall','./Buildings/');
//一個(gè)礦場(chǎng)
$player->building[] = $creator->Creat('Mine','./Buildings/');
}
//初始化人口上限
public function giveSource($player)
{
$player->population= 10;
$player->gold= 1000;
$player->wood= 100;
}
}
分享:解析Windows XP系統(tǒng)下安裝apache+php+mysqlApache和mysql的安裝較簡(jiǎn)單,主要是安裝前請(qǐng)保證80端口未被占用 比如 iis 以前安裝過的apache mysql 先停止運(yùn)行phpmyadmin,主要是配置文件的問題,把phpMyAdmin安裝目錄下Libraries目錄下面的Config.default.php復(fù)制到PHPmyAdmin根目錄下,改 名為Config.in
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁(yè)面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪問控制的和運(yùn)算符優(yōu)先級(jí)介紹
- 關(guān)于PHP語(yǔ)言構(gòu)造器介紹
- php/js獲取客戶端mac地址的實(shí)現(xiàn)代碼
- php5.5新數(shù)組函數(shù)array_column使用
- PHP preg_match的匹配多國(guó)語(yǔ)言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
- 相關(guān)鏈接:
- 教程說(shuō)明:
PHP教程-談從魔獸看PHP設(shè)計(jì)模式
。