談從魔獸看PHP設(shè)計模式(2)_PHP教程
好了,到這里初始化代碼就寫好了,現(xiàn)在還差一個控制這些初始化得類,也就是封裝他們:
<?php
class initialController {
//構(gòu)造函數(shù),參數(shù)為玩家的數(shù)組
public function __construct($playerArray)
{
foreach ($playerArray as $player)
{
switch ($player->race)
{
case 'NighyElf':
$initialController = new NighyElfInitial();break;
case 'ORC':
$initialController = new ORCInitial();break;
}
$initialController->giveArmy($player);
$initialController->giveBuilding($player);
$initialController->giveSupply($player);
}
}
}
最后就是簡單這么一調(diào)用,就OK:
<?php
//有兩個精靈族兩個獸族
$playerArray = array(new player('NighyElf'), new player('NighyElf'), new player('ORC'), new player('ORC'));
//進行初始化工作
$initialController = new initialController($playerArray);
這就是策略模式,他將不同情況下的算法封裝在一起。Zend framework中的Zend_Application_Resource就是用策略模式來設(shè)計的。
三、工廠模式:
問題的提出:
最初在設(shè)計模式一書中,許多設(shè)計模式都鼓勵使用松散耦合。要理解這個概念,讓我們最好談一下許多開發(fā)人員從事大型系統(tǒng)的艱苦歷程。在更改一個代碼片段時,就會發(fā)生問題,系統(tǒng)其他部分 —— 您曾認為完全不相關(guān)的部分中也有可能出現(xiàn)級聯(lián)破壞。
該問題在于緊密耦合。系統(tǒng)某個部分中的函數(shù)和類嚴重依賴于系統(tǒng)的其他部分中函數(shù)和類的行為和結(jié)構(gòu)。您需要一組模式,使這些類能夠相互通信,但不希望將它們緊密綁定在一起,以避免出現(xiàn)聯(lián)鎖。
在大型系統(tǒng)中,許多代碼依賴于少數(shù)幾個關(guān)鍵類。需要更改這些類時,可能會出現(xiàn)困難。例如,假設(shè)您有一個從文件讀取的 User 類。您希望將其更改為從數(shù)據(jù)庫讀取的其他類,但是,所有的代碼都引用從文件讀取的原始類。這時候,使用工廠模式會很方便。
工廠模式是一種類,它具有為您創(chuàng)建對象的某些方法。您可以使用工廠類創(chuàng)建對象,而不直接使用 new。這樣,如果您想要更改所創(chuàng)建的對象類型,只需更改該工廠即可。使用該工廠的所有代碼會自動更改。
問題的解決:
呵呵,估計有些phper沒看懂吧,沒關(guān)系,那是我從其他地方抄的,我們下面還是通過魔獸來進行吧。這一部分,我看都已經(jīng)有前人寫好了,我就基本上照抄了,請前人不要見怪啊。呵呵。
前面選了暗夜精靈族(Nighy Elf),和獸族(ORC),因為小精靈(Wisp)能建造建筑,還能自爆。所以根據(jù)這個我們下面先寫個小精靈(Wisp)的類。
<?php
class Wisp
{
private $mHealthPoint = 120;//這是小精靈的血量
private $mArmor = 0;//這是小精靈的護甲
//小精靈能建造建筑
public function Build()
{
echo '精靈建造建筑咯。<br/>';
}
//每個小精靈被造出來時還會占用一個人口
public function __construct()
{
echo '你已經(jīng)建造了一個小精靈。<br/>';
//這里是增加已有人口的代碼
}
//每個小精靈死亡會減少你占用的人口
public function __destruct()
{
//這里是減少已有人口的代碼
}
}
把這些代碼放在Arms/ Wisp.php中。
啊,還有還有,還有苦工(Peon)的類
<?php
class Peon
{
private $mHealthPoint = 250;//這是苦工的血量
private $mArmor = 0;//這是苦工的護甲
//苦工能建造建筑
public function Build()
{
echo '苦工建造建筑咯。<br/>';
}
//每個苦工被造出來時還會占用一個人口
public function __construct()
{
echo '你已經(jīng)建造了一個苦工。<br/>';
//這里是增加已有人口的代碼
}
//每個苦工死亡會減少你占用的人口
public function __destruct()
{
//這里是減少已有人口的代碼
}
}
把這些代碼放在Arms/ Peon.php中。
等等,這樣豈不是很復(fù)雜,魔獸里面還有那么多的兵種,另外都還有兩個種族,每次創(chuàng)建一個兵就要new一個,要是記不住這個兵的類名,豈不是new不了?而且如果一個兵是一個類,放在一個文件里,那是不是一開始就要把所有的幾十上百個文件都include一次啊,那效率可想而知啊。
嘿嘿,當然是有解決辦法的啊,我們再寫一個類把這些類都封裝起來,這個把兵種都封裝起來的類我們稱之為工廠類,他可以像生產(chǎn)產(chǎn)品一樣,來創(chuàng)建兵,幫我們對其實例化。下面我們就來看這個類怎么實現(xiàn)吧。
<?php
class CreatArms
{
public function __construct(){}
public function Creat($arms,$path = '')
{
include $path.$arms.'.php'; //包含要這個類的文件
return new $arms; //返回你創(chuàng)建的兵種對象的句柄
}
}
這樣,即使在兵種多樣的情況下,我們?nèi)匀豢梢院芊奖愕貙嵗?/p>
$creator = new CreatArms();
$w1 = $creator->Creat('兵種名','前綴或路徑');
例如創(chuàng)建小精靈:
$creator = new CreatArms();//不管創(chuàng)建啥,我都只要使用這個類
$w1 = $creator->Creat(‘Wisp’,’./Arms/’);//創(chuàng)建一個小精靈
$w1->Build();//讓小精靈造建筑
這就是傳說中的工廠模式,通過工廠模式,對于如論壇那種有很多種用戶的,特別是為了以后擴展比較方便的,采用工廠模式,是個很好的解決方法。在zend framework中的Zend_Form、Zend_Filter、Zend_Validate就是用工廠模式來構(gòu)架的。
四、觀察者模式:
問題的提出:
觀察者模式為您提供了避免組件之間緊密耦合的另一種方法。該模式非常簡單:一個對象通過添加一個方法(該方法允許另一個對象,即觀察者 注冊自己)使本身變得可觀察。當可觀察的對象更改時,它會將消息發(fā)送到已注冊的觀察者。這些觀察者使用該信息執(zhí)行的操作與可觀察的對象無關(guān)。結(jié)果是對象可以相互對話,而不必了解原因。
問題的解決:
呵呵,上面還是抄的,看不懂沒關(guān)系,我們今天重點是玩魔獸。
已經(jīng)造了很長時間的兵了,現(xiàn)在可以出去帶兵打仗了,如果我去打電腦的獸族,那么電腦與那個獸族同盟的精靈族就會過來幫忙。那么如何讓他知道自己的同盟受攻擊了呢。現(xiàn)在我們就來討論這個問題。
首先我們寫一下結(jié)盟的抽象類:
<?php
abstract class abstractAlly
{
//放置觀察者的集合,這里以簡單的數(shù)組來直觀演示
protected $oberserverCollection;
//增加觀察者的方法,參數(shù)為觀察者(也是玩家)
public function addOberserver($oberserver)
{
$this->oberserverCollection[] = new oberserver($oberserver);
}
//將被攻擊的電腦的名字通知各個觀察者
public function notify($beAttackedPlayerName)
{
//把觀察者的集合循環(huán)
foreach ($this->oberserverCollection as $oberserver)
{
//調(diào)用各個觀察者的救援函數(shù),參數(shù)為被攻擊的電腦的名字,if用來排除被攻擊的電腦的觀察者
if($oberserver->name != $beAttackedPlayerName)
$oberserver->help($beAttackedPlayerName);
}
}
abstract public function beAttacked($beAttackedPlayer);
}
下面我們就寫具體的結(jié)盟類:
<?php
class Ally extends abstractAlly
{
//構(gòu)造函數(shù),將所有電腦玩家的名稱的數(shù)組作為參數(shù)
public function __construct($allPlayer)
{
//把所有電腦玩家的數(shù)組循環(huán)
foreach ($allPlayer as $player)
{
//增加觀察者,參數(shù)為各個電腦玩家的名稱
$this->addOberserver($player);
}
}
//將被攻擊的電腦的名字通知各個觀察者
public function beAttacked($beAttackedPlayerName)
{
//調(diào)用各個觀察者的救援函數(shù),參數(shù)為被攻擊的電腦的名字,if用來排除被攻擊的電腦的觀察者
$this->notify($beAttackedPlayerName);
}
}
接著在二、策略模式中我們定義的player類中加入一個help方法
public help($beAttackedPlayerName)
{
//這里簡單的輸出,誰去救誰,最后加一個換行,便于顯示
echo $this->name." help ".$beAttackedPlayerName."<br />";
}
這樣就行了。最后就是仿真了。
<?php
//先設(shè)置敵方電腦
$allComputePlayer = array('NighyElf2', 'ORC2');
//新建電腦結(jié)盟
$Ally = new Ally($allComputePlayer);
//假設(shè)我進攻了電腦的獸族
$Ally->beAttacked('ORC2');
這樣結(jié)盟的另一家就能接到通知,去救援。觀察者模式主要就是用在這種情況下。可以將某個狀態(tài)變化立即通知到相關(guān)的對象,相關(guān)的對象就可以采用相應(yīng)的策略。例如,zend framework中的Zend_Message就是用的觀察者模式。
分享:解析Windows XP系統(tǒng)下安裝apache+php+mysqlApache和mysql的安裝較簡單,主要是安裝前請保證80端口未被占用 比如 iis 以前安裝過的apache mysql 先停止運行phpmyadmin,主要是配置文件的問題,把phpMyAdmin安裝目錄下Libraries目錄下面的Config.default.php復(fù)制到PHPmyAdmin根目錄下,改 名為Config.in
- 相關(guān)鏈接:
- 教程說明:
PHP教程-談從魔獸看PHP設(shè)計模式(2)。