http://www.ibm.com/developerworks/cn/opensource/os-php-designpatterns/
简介: PHP V5 的面向对象特性使您能够实现设计模式来改进代码设计。通过这种方式改进代码设计,代码在进行修改时将变得更加易读、更易维护且更加健壮。
设计模式 一书介绍了很多此类概念。当时,我还在学习面向对象 (OO),因此我发现那本书中有许多概念都很难领会。但是,随着越来越熟悉 OO 概念 —— 尤其是接口和继承的使用 —— 我开始看到设计模式中的实际价值。作为一名应用程序开发人员,即使从不了解任何模式或者如何及何时使用这些模式,对您的职业生涯也没有什么大的影响。但 是,我发现了解这些模式以及 developerWorks 文章 “五种常见 PHP 设计模式” 中介绍的那些模式的优秀知识后(请参阅 参考资料),您可以完成两件事情:
有句谚语说得好:“当您手中拿着一把锤子时,所有事物看上去都像钉子”。当您认为自己找到一个优秀模式时,您可能会尝试到处使用它,即使在不应当使用它的位置。记住您必须考虑正在学习的模式的使用目的,不要为了使用模式而把这些模式强行应用到应用程序的各个部分中。
本文将介绍可用于改进 PHP 代码的五个模式。每个模式都将介绍一个特定场景。可以在 下载 部分中获得这些模式的 PHP 代码。
要发挥本文的最大功效并使用示例,需要在计算机中安装以下软件:
- PHP V5 或更高版本(本文是使用 PHP V5.2.4 撰写的)
- 压缩程序,例如 WinZIP(用于压缩可下载的代码归档)
注:虽然您也可以使用纯文本编辑器,但是我发现拥有语法高亮显示和语法纠错功能的编辑器真的很有帮助。本文中的示例是使用 Eclipse PHP Development Tools (PDT) 编写的。
在需要将一类对象转换成另一类对象时,请使用适配器模式。通常,开发人员通过一系列赋值代码来处理此过程,如清单 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
对象的规则发生更改时。记住,以模块化风格设计代码的主要优点之一就是,在业务领域发生一些更改时或者需要向软件中添加新功能时尽可能少的使用更改。即使在执行普通任务(例如把一个对象的属性值赋给另一个对象)时,也请考虑使用此模式。
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 显示了适配器模式的类图。
编写适配器的替代方法 —— 并且是推荐方法 —— 是实现一个接口来修改行为,而不是扩展对象。这是一种非常干净的、创建适配器的方法并且没有扩展对象的缺点。使用接口的缺点之一是需要把实现添加到适配器类中,如图 2 所示:
迭代器模式将提供一种通过对象集合或对象数组封装迭代的方法。如果需要遍历集合中不同类型的对象,则使用这种模式尤为便利。
查看上面清单 1 中的电子邮件和物理地址示例。在添加迭代器模式之前,如果要遍历个人地址,则可能要遍历物理地址并显示这些地址,然后遍历个人电子邮件地址并显示这些地址,然后遍历个人 IM 地址并显示这些地址。非常复杂的遍历!
相反,通过实现迭代器,您只需要调用 while($itr->hasNext())
并处理下一个条目 $itr->next()
返回。清单 3 中显示了一个迭代器示例。迭代器功能强大,因为您可以添加要遍历的新类型条目,并且无需更改遍历条目的代码。例如,在 Person
示例中,可以添加 IM 地址数组;只需更新迭代器,无需更改遍历地址的任何代码。
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 显示了迭代器模式的类图。
考虑清单 4 中的代码样例。这段代码的目的是要把许多功能添加到 Build Your Own Car 站点的汽车中。每个汽车模型都有更多功能及相关价格。如果只针对两个模型,使用 if then
语句添加这些功能十分平常。但是,如果出现了新模型,则必须返回查看代码并确保语句对新模型工作正常。
require('classes.php'); $auto = new Automobile(); $model = new BaseAutomobileModel(); $model = new SportAutomobileModel($model); $model = new TouringAutomobileModel($model); $auto->setModel($model); $auto->printDescription(); |
进入装饰器模式,该模式允许您通过一个优秀整洁的类将此功能添加到 AutomobileModel
。每个类仅仅关注其价格、选项以及添加到基本模型的方式。
图 4 显示了装饰器模式的类图。
装饰器模式的优点是可以轻松地同时跟踪库的多个装饰器。
如果您拥有流对象的使用经验,则一定使用过装饰器。大多数流结构(例如输出流)都是接受基本输入流的装饰器,然后通过添加附加功能来装饰它 —— 例如从文件输入流、从缓冲区输入流,等等。
委托模式将提供一种基于各种条件委托行为的方法。考虑清单 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()
之类的方法时设置对相应对象的内部引用。如果处理各个包的条件发生更改或者使用新的送货类型时,则使用此模式尤为便利。
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 显示了委托模式的类图。
状态模式类似于命令模式,但是意图截然不同。考虑下面的代码。
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 中的代码完成的工作与初始代码相同,但是用于处理状态的逻辑已经被放入每个状态的一个对象中。为了演示使用设计模式的优点,假定不久以后,这些机器人发现 它们不应在处于机器人模式时关闭。实际上,如果它们关闭,它们必须先切换到汽车模式。如果它们已经处于汽车模式下,则机器人将关闭。使用状态模式,对代码 的更改十分微小。
$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"); |
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 中一个不太明显的地方就是状态模式中的每个对象都有对上下文对象(机器人)的引用,因此每个对象都可以把状态提升到相应的状态。
在 PHP 代码中使用设计模式可以使代码更容易阅读、更易维护。通过使用已经建立的模式,您将从通用的设计结构中获益,从而允许团队的其他开发人员了解代码的意图。它还使您可以从其他设计者完成的工作中获益,因此无需从失败的设计理念中吸取教训
相关推荐
在IT行业中,jQuery、PHP和PHP设计模式是三个至关重要的概念,它们构成了现代Web应用程序的基础。下面将分别详细探讨这三个领域的关键知识点。 首先,jQuery是一个高效、简洁的JavaScript库,它极大地简化了...
使用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案。 4. Laravel框架的历史发展 Laravel框架由...
本文实例讲述了PHP设计模式之装饰器模式定义与用法。分享给大家供大家参考,具体如下: 什么是装饰器模式 作为一种结构型模式, 装饰器(Decorator)模式就是对一个已有结构增加”装饰”. 适配器模式, 是为现在有结构...
状态模式是一种行为设计模式,它允许一个对象在其内部状态改变时,改变它的行为。状态模式可以看作是一种面向对象的方法,用以解决一个对象因状态不同而导致的行为变化的问题。 状态模式的核心思想是将状态相关的...
适配器模式(Adapter Pattern)是软件设计中一种非常重要的结构型模式。...总之,适配器模式是PHP软件开发中非常实用的设计模式之一,能够帮助开发者在复杂多变的环境中更好地维护软件的可扩展性和复用性。
书中将详细阐述如何定义和实例化类,如何使用属性和方法,以及如何利用接口和抽象类来实现设计模式。OOP使得代码更易于维护和扩展,是现代软件开发的重要组成部分。 此外,本书还将涵盖PHP5的错误处理和异常处理...
PEAR创始人Stig Saether Bakken,PHP核心贡献者Derick Rethans三大高手合力而作:本书几乎囊括了PHP 5所有的新特性,包括PHP 5所有的新功能,PHP 5的面向对象编程方法和设计模式,以及PHP 5的新的数据库连接处理、...
本文实例讲述了PHP设计模式之装饰器模式定义与用法。分享给大家供大家参考,具体如下: 装饰器模式: 如果已有对象的部分内容或功能性发生改变,但是不需要修改原始对象的结构或不使用继承,动态的扩展一个对象的...
在了解PHP设计模式之装饰模式应用案例详解之前,首先要明确什么是装饰模式。装饰模式是一种结构型设计模式,它的目的是在不修改原有对象结构的前提下,向对象动态添加新的功能。这种模式通过创建一个装饰类来包装...
单例模式是软件设计模式中的一种,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于数据库连接、缓存管理、日志记录等场景,以避免资源的重复创建和管理,提高系统效率。在PHP中,单例...
PEAR创始人Stig Saether Bakken,PHP核心贡献者Derick Rethans三大高手合力而作:本书几乎囊括了PHP 5所有的新特性,包括PHP 5所有的新功能,PHP 5的面向对象编程方法和设计模式,以及PHP 5的新的数据库连接处理、...
适配器模式是软件设计模式中的一种,它能够将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间。适配器模式不仅可以解决不同类的兼容性问题,还能解决新旧接口的兼容性问题,以及...
《基于PHP办公自动化系统的设计与实现》是一篇深入探讨如何运用PHP技术构建高效、便捷的办公自动化系统的专业论文。PHP,全称为“PHP:Hypertext Preprocessor”,是一种广泛使用的开源脚本语言,尤其在Web开发领域...
设计模式-创新-ObjectPool 对象组模式是一种软件创作设计模式,用于初始化类实例的成本非常高的情况。 基本上,对象组是一个包含一定数量对象的容器。 因此,从池中删除对象时,在将对象放回之前,该对象在池中不...
本书的核心内容包括:PHP基础语法、函数、面向对象编程、PHP类、常见的设计模式、正则表达式、PHP操作图像和文件、MVC架构思想、ThinkPHP框架、NoSQL与MySQL等。另外,还介绍了当前热点的O2O网站开发和App后台开发的...
- 代码结构清晰,遵循 MVC(模型-视图-控制器)设计模式,便于后期维护和扩展。 - 使用版本控制系统(如 Git)进行代码管理,方便团队协作。 在"grxxdjb"这个压缩包中,可能包含了整个项目的源代码、数据库脚本、...
11. **MVC模式**:Model-View-Controller(模型-视图-控制器)架构模式是Web开发中常用的设计模式。虽然简单项目可能不严格遵循MVC,但理解其原理有助于理解系统结构。 12. **文件上传**:如果新闻系统支持图片或...
另外,它还引入了匿名类(anonymous classes),使得动态创建类变得更加便捷,这对于实现某些设计模式或临时需求非常有用。 最后,PHP7还改进了内存管理,包括更好的垃圾回收机制,降低了内存占用,提升了系统的...
系统架构方面,该酒店管理系统可能采用了MVC(Model-View-Controller)设计模式。Model代表数据模型,处理业务逻辑和数据库交互;View负责展示数据;Controller作为桥梁,接收用户请求并调用Model和View。这种模式...