从魔兽看PHP设计模式_PHP
前段时间看到有人用魔兽来解释设计模式,感觉很有意思,于是我把它改了改,又添加了些设计模式内容,今天发出来。有些地方借鉴了前人的内容,没有注明,请前人不要见怪啊。
这里用大家感兴趣的魔兽3来讨论PHP的几种常见的设计模式:单件模式、策略模式、工厂模式、观察者模式。今天就讲这四个吧,以后继续。
这些设计模式,都是针对面向对象来说的,所以都用PHP5,另外在这里我想说的是PHP4从2008年8月8日(我记得是和北京奥运会同一天,没查证,呵呵)的时候官方就发了最后一个PHP4的补丁,这意味这PHP4的时代已经终结,所以,我建议大家现在就别理PHP4吧,就以PHP5来说吧。
一、单件模式:
问题的提出:
某些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。
问题的解决:
那么下面我们就开始玩魔兽吧。首先双击war3.exe,这时候就开始运行魔兽了。我们用代码来实现吧。
class War3
{
public function __construct()
{
echo "War3 is Running.","
";
}
}
$war = new War3();
运行!很好,输出
War3 is Running.
我们已经可以开始游戏了,但是,如果我在代码末尾再加入
$war2 = new War3();
$war3 = new War3();
会怎么样呢?我们试试,输出结果:
War3 is Running.
War3 is Running.
War3 is Running.
完了,如果不小心双击了两次就开了3个魔兽,那如果再双击几次,那电脑肯定爆掉。。。我们还是来想想解决方法吧。
既然我们不能这么随意的就把这个类实例化了,那么我们就把构造函数改成私有方法。
class War3
{
private function __construct()
{
echo "War3 is Running.","
";
}
}
可是私有变量外部是无法访问的,这样以来,我们就连一个都打不开了啊。别急,我们再给他加一个不用通过实例化,外部也能访问的函数,那就是静态函数,
class War3
{
private function __construct()
{
echo "War3 is Running.","
";
}
public static function runWar()
{
}
}
通过这个静态的方法runWar()我们来控制类War3的实例化,那么还缺上一个标识,我们再创建一个标识,通过这个标识来表示我们的类是否已经实例化,如果实例化,直接返回句柄就行了。
把类修改成
class War3
{
protected static $_instance = null;
private function __construct()
{
echo "War3 is Running.","
";
}
public static function runWar()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
当然,我们运行魔兽时的实例化也要换种方法,就通过
$war = War3::runWar();
就能开始玩魔兽了,好了,下面把完整的代码附上来:
class War3
{
protected static $_instance = null;
private function __construct()
{
echo "War3 is Running.","
";
}
public static function runWar()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
$war = War3::runWar();
$war2 = War3::runWar();
$war3 = War3::runWar();
运行一下,结果是:
War3 is Running.
太好了,我双击了这么多次,也就只运行了一个魔兽,现在随便你怎么打开,机子都不会爆掉了。
这就是传说中的单价模式,主要用于一些很占资源的而且实例仅有一个实例就够用的东西,比如,zend framework中的Zend_Controller_Front前端控制器,就是采用单价模式来设计的,大家有兴趣的话可以看看那个。
二、策略模式:
问题的提出:
在此模式中,算法是从复杂类提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择。思考一下搜索引擎的几个部分 —— 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。
问题的解决:
呵呵,不讲那么复杂,刚才魔兽好不容易打开了,我们还是玩魔兽好了。
下面我们选battle,哇好多种族啊,有人族(Human),兽族(ORC),暗夜精灵族(Nighy Elf),不死族(Undead)。我选精灵族(Nighy Elf),再选一个精灵族和两个兽族(ORC),一个兽族和我是一家的,另一个精灵族和兽族是另一家的。
每一个玩家在进入游戏后都会得到一些资源,如一个大厅,五个小精灵(苦工)和一个矿山。这些可以称为是初始化的一些东西,这里我们就可以用到策略模式来封装这些初始化。
进入正题,首先我们来构建一个玩家类:
class player
{
//玩家名字
protected $_name;
//种族
protected $_race;
//队伍
protected $army;
//建筑
protected $building;
//人口
protected $population;
//黄金
protected $gold;
//木材
protected $wood;
//构造函数,设定所属种族
public function __construct($race)
{
$this->race = $race;
}
//__get()方法用来获取保护属性
private function __get($property_name)
{
if(isset($this->$property_name)) {
return($this->$property_name);
}
else {
return(NULL);
}
}
//__set()方法用来设置保护属性
private function__set($property_name,$value)
{
$this->$property_name=$value;
}
}
接着,我们再建一个玩家初始化的接口,
interface initialPlayer
{
//制造初始化的部队
public function giveArmy($player);
//制造初始化的建筑
public function giveBuilding($player);
//初始化资源
public function giveSource($player);
}
好了,到这里我们就该对这个接口来实现了,为了方便,我只选了两个种族,就只写这两个种族的初始化了:
首先是精灵族:
class NighyElfInitial implements initialPlayer
{
//制造初始化的部队
public function giveArmy($player)
{
//五个小精灵
for($i=0; $i
{
$creator = new CreatArms();//这个是创建部队类,在后面得工厂模式中会用到,这里我就不多说了
$player->army[] = $creator->Creat('Wisp','./Arms/');
}
}
//制造初始化的建筑
public function giveBuilding($player)
{
$creator = new CreatBuildings();
//一个基地
$player->building[] = $creator->Creat('TownHall','./Buildings/');
//一个矿场
$player->building[] = $creator->Creat('Mine','./Buildings/');
}
//初始化人口上限
public function giveSource($player)
{
$player->population= 10;
$player->gold= 1000;
$player->wood= 100;
}
}
接下来是兽族:
class ORCInitial implements initialPlayer
{
//制造初始化的部队
public function giveArmy($player)
{
//五个苦工
for($i=0; $i
{
$creator = new CreatArms();//这个是创建部队类,在后面得工厂模式中会用到,这里我就不多说了
$player->army[] = $creator->Creat('Peon','./Arms/');
}
}
//制造初始化的建筑
public function giveBuilding($player)
{
$creator = new CreatBuildings();
//一个基地
$player->building[] = $creator->Creat('TownHall','./Buildings/');
//一个矿场
$player->building[] = $creator->Creat('Mine','./Buildings/');
}
//初始化人口上限
public function giveSource($player)
{
$player->population= 10;
$player->gold= 1000;
$player->wood= 100;
}
}

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

會話劫持可以通過以下步驟實現:1.獲取會話ID,2.使用會話ID,3.保持會話活躍。在PHP中防範會話劫持的方法包括:1.使用session_regenerate_id()函數重新生成會話ID,2.通過數據庫存儲會話數據,3.確保所有會話數據通過HTTPS傳輸。

SOLID原則在PHP開發中的應用包括:1.單一職責原則(SRP):每個類只負責一個功能。 2.開閉原則(OCP):通過擴展而非修改實現變化。 3.里氏替換原則(LSP):子類可替換基類而不影響程序正確性。 4.接口隔離原則(ISP):使用細粒度接口避免依賴不使用的方法。 5.依賴倒置原則(DIP):高低層次模塊都依賴於抽象,通過依賴注入實現。

在PHPStorm中如何進行CLI模式的調試?在使用PHPStorm進行開發時,有時我們需要在命令行界面(CLI)模式下調試PHP�...

PHP8.1中的枚舉功能通過定義命名常量增強了代碼的清晰度和類型安全性。 1)枚舉可以是整數、字符串或對象,提高了代碼可讀性和類型安全性。 2)枚舉基於類,支持面向對象特性,如遍歷和反射。 3)枚舉可用於比較和賦值,確保類型安全。 4)枚舉支持添加方法,實現複雜邏輯。 5)嚴格類型檢查和錯誤處理可避免常見錯誤。 6)枚舉減少魔法值,提升可維護性,但需注意性能優化。

如何在系統重啟後自動設置unixsocket的權限每次系統重啟後,我們都需要執行以下命令來修改unixsocket的權限:sudo...

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。
