首頁 php教程 php手册 PHP 设计模式(二)

PHP 设计模式(二)

Jun 06, 2016 pm 08:02 PM
php 概念 設計模式

设计模式 一书介绍了很多此类概念。当时,我还在学习面向对象 (OO),因此我发现那本书中有许多概念都很难领会。但是,随着越来越熟悉 OO 概念 —— 尤其是接口和继承的使用 —— 我开始看到设计模式中的实际价。作为一名应用程序开发人员,即使从不了解任何


设计模式 一书介绍了很多此类概念。当时,我还在学习面向对象 (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();
<span>/* Here's the assignment code, where I'm assigning values 
  from one object to another... */</span>
$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. 适配器模式的类图
PHP 设计模式(二)

替代方法

编写适配器的替代方法 —— 并且是推荐方法 —— 是实现一个接口来修改行为,而不是扩展对象。这是一种非常干净的、创建适配器的方法并且没有扩展对象的缺点。使用接口的缺点之一是需要把实现添加到适配器类中,如图 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. 迭代器模式的类图
PHP 设计模式(二)

回页首

装饰器 (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. 装饰器模式的类图
PHP 设计模式(二)

装饰器模式的优点是可以轻松地同时跟踪库的多个装饰器。

如果您拥有流对象的使用经验,则一定使用过装饰器。大多数流结构(例如输出流)都是接受基本输入流的装饰器,然后通过添加附加功能来装饰它 —— 例如从文件输入流、从缓冲区输入流,等等。

回页首

委托模式

委托模式将提供一种基于各种条件委托行为的方法。考虑清单 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. 委托模式的类图
PHP 设计模式(二)

回页首

状态模式

状态模式类似于命令模式,但是意图截然不同。考虑下面的代码。

清单 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()  
    {
        <span>/* First, turn into a vehicle */
        $this->robot->setState(new VehicleRobotState($this->robot));
        $this->robot->powerDown();</span>
    }
    
    public function turnIntoVehicle()  
    {
        /* implementation... */
    }
    
    public function turnIntoRobot() 
    {
        /* implementation... */
    }
}
登入後複製

图 6 中一个不太明显的地方就是状态模式中的每个对象都有对上下文对象(机器人)的引用,因此每个对象都可以把状态提升到相应的状态。

图 6. 状态模式的类图
PHP 设计模式(二)

回页首

结束语

在 PHP 代码中使用设计模式可以使代码更容易阅读、更易维护。通过使用已经建立的模式,您将从通用的设计结构中获益,从而允许团队的其他开发人员了解代码的意图。它还使您可以从其他设计者完成的工作中获益,因此无需从失败的设计理念中吸取教训。


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Java教學
1665
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP和Python:代碼示例和比較 PHP和Python:代碼示例和比較 Apr 15, 2025 am 12:07 AM

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

See all articles