亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

另外五個 PHP 設計模式

系統 2923 0

另外五個 PHP 設計模式

級別: 中級

Nathan A. Good ( mail@nathanagood.com ), 高級信息工程師, 顧問

2008 年 4 月 28 日

PHP V5 的面向對象特性使您能夠實現設計模式來改進代碼設計。通過這種方式改進代碼設計,代碼在進行修改時將變得更加易讀、更易維護且更加健壯。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

設計模式 一書介紹了很多此類概念。當時,我還在學習面向對象 (OO),因此我發現那本書中有許多概念都很難領會。但是,隨著越來越熟悉 OO 概念 —— 尤其是接口和繼承的使用 —— 我開始看到設計模式中的實際價值。作為一名應用程序開發人員,即使從不了解任何模式或者如何及何時使用這些模式,對您的職業生涯也沒有什么大的影響。但是,我發現了解這些模式以及 developerWorks 文章 “五種常見 PHP 設計模式” 中介紹的那些模式的優秀知識后(請參閱 參考資料 ),您可以完成兩件事情:

啟用高帶寬會話
如果了解設計模式,您將能夠更快地構建可靠的 OO 應用程序。但當整個開發團隊知道各種模式時,您可以突然擁有非常高的帶寬會話。您不再需要討論將到處使用的所有類。相反,您可以與其他人談論模式?!拔乙谶@里引用一個單例(singleton),然后使用迭代器遍歷對象集合,然后……” 比遍歷構成這些模式的類、方法和接口快很多。單是通信效率一項就值得花時間以團隊的形式通過會話來研究模式。
減少痛苦的教訓
每個設計模式都描述了一種經過驗證的解決常見問題的方法。因此,您無需擔心設計是不是正確的,只要您已經選擇了提供所需優點的模式。

缺陷

有句諺語說得好:“當您手中拿著一把錘子時,所有事物看上去都像釘子”。當您認為自己找到一個優秀模式時,您可能會嘗試到處使用它,即使在不應當使用它的位置。記住您必須考慮正在學習的模式的使用目的,不要為了使用模式而把這些模式強行應用到應用程序的各個部分中。

本文將介紹可用于改進 PHP 代碼的五個模式。每個模式都將介紹一個特定場景。可以在 下載 部分中獲得這些模式的 PHP 代碼。

要求

要發揮本文的最大功效并使用示例,需要在計算機中安裝以下軟件:

  • PHP V5 或更高版本(本文是使用 PHP V5.2.4 撰寫的)
  • 壓縮程序,例如 WinZIP(用于壓縮可下載的代碼歸檔)

注: 雖然您也可以使用純文本編輯器,但是我發現擁有語法高亮顯示和語法糾錯功能的編輯器真的很有幫助。本文中的示例是使用 Eclipse PHP Development Tools (PDT) 編寫的。





回頁首


適配器模式

在需要將一類對象轉換成另一類對象時,請使用適配器模式。通常,開發人員通過一系列賦值代碼來處理此過程,如清單 1 所示。適配器模式是整理此類代碼并在其他位置重用所有賦值代碼的優秀方法。此外,它還將隱藏賦值代碼,如果同時還要設定格式,這樣可以極大地簡化工作。


清單 1. 使用代碼在對象之間賦值

                            
class AddressDisplay
{
    private $addressType;
    private $addressText;

    public function setAddressType($addressType)
    {
        $this->addressType = $addressType;
    }

    public function getAddressType()
    {
        return $this->addressType;
    }

    public function setAddressText($addressText)
    {
        $this->addressText = $addressText;
    }

    public function getAddressText()
    {
        return $this->addressText;
    }
}

class EmailAddress
{
    private $emailAddress;
    
    public function getEmailAddress()
    {
        return $this->emailAddress;
    }
    
    public function setEmailAddress($address)
    {
        $this->emailAddress = $address;
    }
}

$emailAddress = new EmailAddress();
/* Populate the EmailAddress object */
$address = new AddressDisplay();

            
              
                /* Here's the assignment code, where I'm assigning values from one object to another... */
              
            
            
$address->setAddressType("email");
$address->setAddressText($emailAddress->getEmailAddress());

          

此示例將使用 AddressDisplay 對象把地址顯示給用戶。 AddressDisplay 對象有兩部分:地址類型和一個格式化的地址字符串。

在實現模式(參見清單 2)后,PHP 腳本將不再需要擔心如何把 EmailAddress 對象轉換成 AddressDisplay 對象。那是件好事,尤其是在 AddressDisplay 對象發生更改時或者控制如何把 EmailAddress 對象轉換成 AddressDisplay 對象的規則發生更改時。記住,以模塊化風格設計代碼的主要優點之一就是,在業務領域發生一些更改時或者需要向軟件中添加新功能時盡可能少的使用更改。即使在執行普通任務(例如把一個對象的屬性值賦給另一個對象)時,也請考慮使用此模式。


清單 2. 使用適配器模式

                            
class EmailAddressDisplayAdapter extends AddressDisplay
{
    public function __construct($emailAddr)
    {
        $this->setAddressType("email");
        $this->setAddressText($emailAddr->getEmailAddress());
    }
}	

$email = new EmailAddress();
$email->setEmailAddress("user@example.com");

$address = new EmailAddressDisplayAdapter($email);

echo($address->getAddressType() . "/n") ;
echo($address->getAddressText());

          

圖 1 顯示了適配器模式的類圖。


圖 1. 適配器模式的類圖
適配器模式的類圖

替代方法

編寫適配器的替代方法 —— 并且是推薦方法 —— 是實現一個接口來修改行為,而不是擴展對象。這是一種非常干凈的、創建適配器的方法并且沒有擴展對象的缺點。使用接口的缺點之一是需要把實現添加到適配器類中,如圖 2 所示:


圖 2. 適配器模式(使用接口)
適配器模式(使用接口)





回頁首


迭代器模式

迭代器模式將提供一種通過對象集合或對象數組封裝迭代的方法。如果需要遍歷集合中不同類型的對象,則使用這種模式尤為便利。

查看上面清單 1 中的電子郵件和物理地址示例。在添加迭代器模式之前,如果要遍歷個人地址,則可能要遍歷物理地址并顯示這些地址,然后遍歷個人電子郵件地址并顯示這些地址,然后遍歷個人 IM 地址并顯示這些地址。非常復雜的遍歷!

相反,通過實現迭代器,您只需要調用 while($itr->hasNext()) 并處理下一個條目 $itr->next() 返回。清單 3 中顯示了一個迭代器示例。迭代器功能強大,因為您可以添加要遍歷的新類型條目,并且無需更改遍歷條目的代碼。例如,在 Person 示例中,可以添加 IM 地址數組;只需更新迭代器,無需更改遍歷地址的任何代碼。


清單 3. 使用迭代器模式遍歷對象

                            
class PersonAddressIterator implements AddressIterator
{
    private $emailAddresses;
    private $physicalAddresses;
    private $position;
    
    public function __construct($emailAddresses)
    {
        $this->emailAddresses = $emailAddresses;
        $this->position = 0;
    }
    
    public function hasNext()
    {
        if ($this->position >= count($this->emailAddresses) || 
            $this->emailAddresses[$this->position] == null) {
            return false;
        } else {
            return true;
        }
    }
    
    public function next()
    {
        $item = $this->emailAddresses[$this->position];
        $this->position = $this->position + 1;
        return $item;
    }
    
}

          

如果把 Person 對象修改為返回 AddressIterator 接口的實現,則在將實現擴展為遍歷附加對象時無需修改使用迭代器的應用程序代碼。您可以使用一個混合迭代器,它封裝了遍歷清單 3 中列出的每種地址的迭代器。本文提供了此類應用示例(請參閱 下載 )。

圖 3 顯示了迭代器模式的類圖。


圖 3. 迭代器模式的類圖
迭代器模式的類圖





回頁首


裝飾器 (decorator) 模式

考慮清單 4 中的代碼樣例。這段代碼的目的是要把許多功能添加到 Build Your Own Car 站點的汽車中。每個汽車模型都有更多功能及相關價格。如果只針對兩個模型,使用 if then 語句添加這些功能十分平常。但是,如果出現了新模型,則必須返回查看代碼并確保語句對新模型工作正常。


清單 4. 使用裝飾器模式添加功能

                            
require('classes.php');

$auto = new Automobile();

$model = new BaseAutomobileModel();

$model = new SportAutomobileModel($model);

$model = new TouringAutomobileModel($model);

$auto->setModel($model);

$auto->printDescription();

          

進入裝飾器模式,該模式允許您通過一個優秀整潔的類將此功能添加到 AutomobileModel 。每個類僅僅關注其價格、選項以及添加到基本模型的方式。

圖 4 顯示了裝飾器模式的類圖。


圖 4. 裝飾器模式的類圖
裝飾器模式的類圖

裝飾器模式的優點是可以輕松地同時跟蹤庫的多個裝飾器。

如果您擁有流對象的使用經驗,則一定使用過裝飾器。大多數流結構(例如輸出流)都是接受基本輸入流的裝飾器,然后通過添加附加功能來裝飾它 —— 例如從文件輸入流、從緩沖區輸入流,等等。





回頁首


委托模式

委托模式將提供一種基于各種條件委托行為的方法。考慮清單 5 中的代碼。這段代碼包含幾個條件。根據條件,代碼將選擇相應類型的對象來處理請求。


清單 5. 使用條件語句來發送送貨請求

                            
pkg = new Package("Heavy Package");
$pkg->setWeight(100);

if ($pkg->getWeight() > 99)
{
	echo( "Shipping " . $pkg->getDescription() . " by rail.");
} else {
	echo("Shipping " . $pkg->getDescription() . " by truck");
}

          

使用委托模式,對象將內在化(internalize)此發送過程,方法為在調用如清單 6 中的 useRail() 之類的方法時設置對相應對象的內部引用。如果處理各個包的條件發生更改或者使用新的送貨類型時,則使用此模式尤為便利。


清單 6. 使用委托模式來發送送貨請求

                            
require_once('classes.php');

$pkg = new Package("Heavy Package");
$pkg->setWeight(100);

$shipper = new ShippingDelegate();

if ($pkg->getWeight() > 99)
{
	$shipper->useRail();
}

$shipper->deliver($pkg);

          

委托將通過調用 useRail() useTruck() 方法來切換處理工作的類,從而提供動態更改行為的優點。

圖 5 顯示了委托模式的類圖。


圖 5. 委托模式的類圖
委托模式的類圖





回頁首


狀態模式

狀態模式類似于命令模式,但是意圖截然不同。考慮下面的代碼。


清單 7. 使用代碼來構建機器人

                            
class Robot 
{

	private $state;

	public function powerUp()
	{
		if (strcmp($state, "poweredUp") == 0)
		{
			echo("Already powered up.../n");
			/* Implementation... */
		} else if ( strcmp($state, "powereddown") == 0) {
			echo("Powering up now.../n");
			/* Implementation... */
		}
	}

	public function powerDown()
	{
		if (strcmp($state, "poweredUp") == 0)
		{
			echo("Powering down now.../n");
			/* Implementation... */
		} else if ( strcmp($state, "powereddown") == 0) {
			echo("Already powered down.../n");
			/* Implementation... */
		}
	}

	/* etc... */

}

          

在此清單中,PHP 代碼表示變成一輛汽車的強大機器人的操作系統。機器人可以啟動、關閉、由汽車變成機器人以及由機器人變成汽車。代碼現已就緒,但是您會看到如果任何規則發生更改或者添加另一個狀態則會變得十分復雜。

現在查看清單 8,其中提供了相同的邏輯處理機器人的狀態,但是這一次把邏輯放入狀態模式。清單 8 中的代碼完成的工作與初始代碼相同,但是用于處理狀態的邏輯已經被放入每個狀態的一個對象中。為了演示使用設計模式的優點,假定不久以后,這些機器人發現它們不應在處于機器人模式時關閉。實際上,如果它們關閉,它們必須先切換到汽車模式。如果它們已經處于汽車模式下,則機器人將關閉。使用狀態模式,對代碼的更改十分微小。


清單 8. 使用狀態模式處理機器人的狀態

                            
$robot = new Robot();
echo("/n");
$robot->powerUp();
echo("/n");
$robot->turnIntoRobot();
echo("/n");
$robot->turnIntoRobot(); /* This one will just give me a message */
echo("/n");
$robot->turnIntoVehicle();
echo("/n");

          


清單 9. 對一個狀態對象的微小更改
                            
class NormalRobotState implements RobotState
{
    private $robot;

    public function __construct($robot)
    {
        $this->robot = $robot;
    }

    public function powerUp()
    {
        /* implementation... */
    }
    public function powerDown()  
    {
        
            
              
                /* First, turn into a vehicle */ $this->robot->setState(new VehicleRobotState($this->robot)); $this->robot->powerDown();
              
            
            
    }
    
    public function turnIntoVehicle()  
    {
        /* implementation... */
    }
    
    public function turnIntoRobot() 
    {
        /* implementation... */
    }
}

          

圖 6 中一個不太明顯的地方就是狀態模式中的每個對象都有對上下文對象(機器人)的引用,因此每個對象都可以把狀態提升到相應的狀態。


圖 6. 狀態模式的類圖
狀態模式的類圖

結束語

在 PHP 代碼中使用設計模式可以使代碼更容易閱讀、更易維護。通過使用已經建立的模式,您將從通用的設計結構中獲益,從而允許團隊的其他開發人員了解代碼的意圖。它還使您可以從其他設計者完成的工作中獲益,因此無需從失敗的設計理念中吸取教訓。

來源: http://www.ibm.com/developerworks/cn/opensource/os-php-designpatterns


另外五個 PHP 設計模式


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!??!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产99久久九九精品免费 | 亚洲高清美女一区二区三区 | 五月婷婷综合激情 | 国产亚洲在线观看 | 亚洲成a人v欧美综合天 | 亚洲成a人片在线v观看 | 亚洲va欧美va国产 | 六月丁香婷婷激情国产 | 四虎成人免费视频 | 欧美一级夜夜爽 视频 | 暴劫倾情无删减在线播放 | 久精品视频村上里沙 | 夜色亚洲| 国产一区二区三区国产精品 | 久久香蕉国产 | 九天玄帝诀王凡小说免费阅读 | 四虎久久精品国产 | 黄色在线免费看 | 亚洲欧洲一区二区三区久久 | 亚洲欧洲视频在线观看 | 国产在线精彩视频 | 精品自拍视频在线观看 | 99精品视频在线这里只有 | 亚洲国产成人久久笫一页 | 成人久久久精品乱码一区二区三区 | 国产精品欧美亚洲区 | 亚洲偷自拍另类图片二区 | 超碰人人操 | 99热这里只有精品5 99热这里只有精品66 | 日韩精品另类天天更新影院 | 日本亚洲国产精品久久 | 亚洲免费中文字幕 | 欧美在线香蕉在线现视频 | 人人爽天天碰天天躁夜夜躁 | 中文字幕日韩专区 | 亚洲日日夜夜 | 97影院理论在线观看 | 国产伦精品一区二区三区四区 | 成人在线观看国产 | 精品一区二区三区视频在线观看 | 欧美日韩在线播放一区二区三区 |