




已阅读5页,还剩20页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
设计模式只是为 Java 架构师准备的 至少您可能一直这样认为。实际上,设计模式对于每个人都很有用。假如这些工具不是 “架构太空人” 的专利,那么他们又是什么?为什么说他们在 PHP 应用程式中很有用?本文解释了这些问题。设计模式 一书将设计模式引入软件社区,该书的作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design(俗称 “四人帮”)。所介绍的设计模式背后的核心概念很简单。经过多年的软件研发实践,Gamma 等人发现了某些具备固定设计的模式,就像建筑师设计房子和建筑物相同,能够为浴室的位置或厨房的构造方式研发模板。使用这些模板或说设计模式 意味着能够更快地设计更好的建筑物。同样的概念也适用于软件。设计模式不但代表着更快研发健壮软件的有用方法,而且还提供了以友好的术语封装大型理念的方法。例如,您能够说您正在编写一个提供松散耦合的消息传递系统,也能够说您正在编写名称为观察者 的模式。用较小的示例展示模式的价值是很困难的。这往往有些大材小用的意味,因为模式实际上是在大型代码库中发挥作用的。本文不展示大型应用程式,所以您需要思索的是在您自己的大型应用程式中应用示例原理的方法 而不是本文演示的代码本身。这不是说您不应该在小应用程式中使用模式。很多良好的应用程式都以小应用程式为起点,逐渐发展到大型应用程式,所以没有理由不以此类扎实的编码实践为基础。既然您已了解了设计模式连同他们的有用之处,现在我们来看看 PHP5 的五种常用模式。工厂模式最初在设计模式 一书中,许多设计模式都鼓励使用松散耦合。要理解这个概念,让我们最好谈一下许多研发人员从事大型系统的艰苦历程。在更改一个代码片段时,就会发生问题,系统其他部分 您曾认为完全不相关的部分中也有可能出现级联破坏。该问题在于紧密耦合 。系统某个部分中的函数和类严重依赖于系统的其他部分中函数和类的行为和结构。您需要一组模式,使这些类能够相互通信,但不希望将他们紧密绑定在一起,以避免出现联锁。在大型系统中,许多代码依赖于少数几个关键类。需要更改这些类时,可能会出现困难。例如,假设您有一个从文档读取的 User 类。您希望将其更改为从数据库读取的其他类,但是,任何的代码都引用从文档读取的原始类。这时候,使用工厂模式会很方便。工厂模式 是一种类,他具备为您创建对象的某些方法。您能够使用工厂类创建对象,而不直接使用 new。这样,假如您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的任何代码会自动更改。清单 1 显示工厂类的一个示列。等式的服务器端包括两个部分:数据库和一组 PHP 页面,这些页面允许您添加反馈、请求反馈列表并获取和特定反馈相关的文章。清单 1. Factory1.php getName().n ); ? IUser 接口定义用户对象应执行什么操作。IUser 的实现称为 User,UserFactory 工厂类则创建 IUser 对象。假如您使用 php 解释器在命令行上运行此代码,将得到如下结果:% php factory1.php Jack % 测试代码会向工厂请求 User 对象,并输出 getName 方法的结果。有一种工厂模式的变体使用工厂方法。类中的这些公共静态方法构造该类型的对象。假如创建此类型的对象很重要,此方法很有用。例如,假设您需要先创建对象,然后配置许多属性。此版本的工厂模式会将该进程封装在单个位置中,这样,不用复制复杂的初始化代码,也不必将复制好的代码在在代码库中到处粘贴。清单 2 显示使用工厂方法的一个示例。清单 2. Factory2.phpgetName().n ); ? 这段代码要简单得多。他仅有一个接口 IUser 和一个实现此接口的 User 类。User 类有两个创建对象的静态方法。此关系可用图 2 中的 UML 表示。在命令行中运行脚本产生的结果和清单 1 的结果相同,如下所示:% php factory2.php Jack % 如上所述,有时此类模式在规模较小的环境中似乎有些大材小用。但是,最好还是学习这种扎实的编码形式,以便应用于任意规模的项目中。单元素模式某些应用程式资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程式中共享数据库句柄,因为在保持连接打开或关闭时,他是一种开销,在获取单个页面的过程中更是如此。单元素模式能够满足此需要。假如应用程式每次包含且仅包含一个对象,那么这个对象就是个单元素(Singleton)。清单 3 中的代码显示了 PHP V5 中的一个数据库连接单元素。清单 3. Singleton.php_handle =& DB:Connect( $dsn, array() ); public function handle() return $this-_handle; print( Handle = .DatabaseConnection:get()-handle().n ); print( Handle = .DatabaseConnection:get()-handle().n ); ? 此代码显示名为 DatabaseConnection 的单个类。您不能创建自已的 DatabaseConnection,因为构造函数是专用的。但使用静态 get 方法,您能够获得且仅获得一个 DatabaseConnection 对象。此代码的 UML 如图 3 所示。图 3. 数据库连接单元素 在两次调用间,handle 方法返回的数据库句柄是相同的,这就是最好的证实。您能够在命令行中运行代码来观察这一点。% php singleton.php Handle = Object id #3 Handle = Object id #3 % 返回的两个句柄是同一对象。假如您在整个应用程式中使用数据库连接单元素,那么就能够在任何地方重用同一句柄。您能够使用全局变量存储数据库句柄,但是,该方法仅适用于较小的应用程式。在较大的应用程式中,应避免使用全局变量,并使用对象和方法访问资源。观察者模式观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式很简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,他会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作和可观察的对象无关。结果是对象能够相互对话,而不必了解原因。一个简单示例是系统中的用户列表。清单 4 中的代码显示一个用户列表,添加用户时,他将发送出一条消息。添加用户时,通过发送消息的日志观察者能够观察此列表。清单 4. Observer.php_observers as $obs ) $obs-onChanged( $this, $name ); public function addObserver( $observer ) $this-_observers = $observer; class UserListLogger implements IObserver public function onChanged( $sender, $args ) echo( $args added to user listn ); $ul = new UserList(); $ul-addObserver( new UserListLogger() ); $ul-addCustomer( Jack ); ? 此代码定义四个元素:两个接口和两个类。IObservable 接口定义能够被观察的对象,UserList 实现该接口,以便将本身注册为可观察。IObserver 列表定义要通过怎样的方法才能成为观察者,UserListLogger 实现 IObserver 接口。图 4 的 UML 中展示了这些元素。假如在命令行中运行他,您将看到以下输出:% php observer.php Jack added to user list % 测试代码创建 UserList,并将 UserListLogger 观察者添加到其中。然后添加一个消费者,并将这一更改通知 UserListLogger。认识到 UserList 不知道日志程式将执行什么操作很关键。可能存在一个或多个执行其他操作的侦听程式。例如,您可能有一个向新用户发送消息的观察者,欢迎新用户使用该系统。这种方法的价值在于 UserList 忽略任何依赖他的对象,他主要关注在列表更改时维护用户列表并发送消息这一工作。此模式不限于内存中的对象。他是在较大的应用程式中使用的数据库驱动的消息查询系统的基础。命令链模式命令链 模式以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理程式发送任意内容。每个处理程式都会自行判断自己能否处理请求。假如能够,该请求被处理,进程停止。您能够为系统添加或移除处理程式,而不影响其他处理程式。清单 5 显示了此模式的一个示例。清单 5. Chain.php_commands = $cmd; public function runCommand( $name, $args ) foreach( $this-_commands as $cmd ) if ( $cmd-onCommand( $name, $args ) ) return; class UserCommand implements ICommand public function onCommand( $name, $args ) if ( $name != addUser ) return false; echo( UserCommand handling addUsern ); return true; class MailCommand implements ICommand public function onCommand( $name, $args ) if ( $name != mail ) return false; echo( MailCommand handling mailn ); return true; $cc = new CommandChain(); $cc-addCommand( new UserCommand() ); $cc-addCommand( new MailCommand() ); $cc-runCommand( addUser, null ); $cc-runCommand( mail, null ); ? 此代码定义维护 ICommand 对象列表的 CommandChain 类。两个类都能够实现 ICommand 接口 一个对邮件的请求作出响应,另一个对添加用户作出响应。 图 5 给出了 UML。图 5. 命令链及其相关命令假如您运行包含某些测试代码的脚本,则会得到以下输出:% php chain.php UserCommand handling addUser MailCommand handling mail % 代码首先创建 CommandChain 对象,并为他添加两个命令对象的实例。然后运行两个命令以查看谁对这些命令作出了响应。假如命令的名称匹配 UserCommand 或 MailCommand,则代码失败,不发生任何操作。为处理请求而创建可扩展的架构时,命令链模式很有价值,使用他能够解决许多问题。策略模式我们讲述的最后一个设计模式是策略模式。在此模式中,算法是从复杂类提取的,因而能够方便地替换。例如,假如要更改搜索引擎中排列页的方法,则策略模式是个不错的选择。思考一下搜索引擎的几个部分 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。作为一个较简单的示例,清单 6 显示了一个用户列表类,他提供了一个根据一组即插即用的策略查找一组用户的方法。 清单 6. Strategy.php_name = $name; public function filter( $record ) return strcmp( $this-_name, $record ) = 0.5; class UserList private $_list = array(); public function _construct( $names ) if ( $names != null ) foreach( $names as $name ) $this-_list = $name; public function add( $name ) $this-_list = $name; public function find( $filter ) $recs = array(); foreach( $this-_list as $user ) if ( $filter-filter( $user ) ) $recs = $user; return $recs; $ul = new UserList( array( Andy, Jack, Lori, Megan ) ); $f1 = $ul-find( new FindAfterStrategy( J ) ); print_r( $f1 ); $f2 = $ul-find( new RandomStrategy() ); print_r( $f2 ); ? 此代码的 UML 如图 6 所示。图 6. 用户列表和用于选择用户的策略 UserList 类是打包名称数组的一个包装器。他实现 find 方法,该方法利用几个策略之一来选择这些名称的子集。这些策略由 IStrategy 接口定义,该接口有两个实现:一个随机选择用户,另一个根据指定名称选择其后的任何名称。运行测试代码时,将得到以下输出:% php strategy.php Array ( 0 = Jack 1 = Lori 2 = Megan ) Array ( 0 = Andy 1 = Megan ) % 测试代码为两个策略运行同一用户列表,并显示结果。在第一种情况中,策略查找排列在 J 后的任何名称,所以您将得到 Jack、Lori 和 Megan。第二个策略随机选取名称,每次会产生不同的结果。在这种情况下,结果为 Andy 和 Megan。策略模式很适合复杂数据管理系统或数据处理系统,二者在数据筛选、搜索或处理的方式方面需要较高的灵活性。结束语本文介绍的仅仅是 PHP 应用程式中使用的几种最常见的设计模式。在设计模式 一书中演示了更多的设计模式。不要因架构的神秘性而放弃。模式是一种绝妙的理念,适用于任何编程语言、任何技能水平。MVC设计模式: MVC模式在网站架构中十分常见。它允许我们建立一个三层结构的应用程式,从代码中分离出有用的层,帮助设计师和开发者协同工作以及提高我们维护和扩展既有程式的能力。视图(View)“视图”主要指我们送到Web浏览器的最终结果?比如我们的脚本生成的HTML。当说到视图时,很多人想到的是模版,但是把模板方案叫做视图的正确性是值得怀疑的。对视图来说,最重要的事情可能是它应该是“自我意识(self aware)”的,视图被渲染(render)时,视图的元素能意识到自己在更大框架中的角色。以XML为例,可以说XML在被解析时,DOM API有着这样的认知?一个DOM树里的节点知道它在哪里和它包含了什么。 (当一个XML文档中的节点用SAX解析时只有当解析到该节点时它才有意义。)绝大多数模板方案使用简单的过程语言和这样的模板标签:some_text some_more_text它们在文档中没有意义,它们代表的意义只是PHP将用其他的东西来替换它。如果你同意这种对视图的松散描述,你也就会同意绝大多数模板方案并没有有效的分离视图和模型。模板标签将被替换成什么存放在模型中。在你实现视图时问自己几个问题:“全体视图的替换容易吗?”“实现一个新视图要多久?” “能很容易的替换视图的描述语言吗?(比如在同一个视图中用SOAP文档替换HTML文档)”模型(Model)模型代表了程序逻辑。(在企业级程序中经常称为业务层(business layer)总的来说,模型的任务是把原有数据转换成包含某些意义的数据,这些数据将被视图所显示。通常,模型将封装数据查询,可能通过一些抽象数据类(数据访问层)来实现查询。举例说,你希望计算英国年度降雨量(只是为了给你自己找个好点的度假地),模型将接收十年中每天的降雨量,计算出平均值,再传递给视图。控制器(controller)简单的说控制器是Web应用中进入的HTTP请求最先调用的一部分。它检查收到的请求,比如一些GET变量,做出合适的反馈。在写出你的第一个控制器之前,你很难开始编写其他的PHP代码。最常见的用法是index.php中像switch语句的结构:display(); ?这段代码混用了面向过程和对象的代码,但是对于小的站点来说,这通常是最好的选择。虽然上边的代码还可以优化。控制器实际上是用来触发模型的数据和视图元素之间的绑定的控件。例子这里是一个使用MVC模式的简单例子。首先我们需要一个数据库访问类,它是一个普通类。db=mysql_pconnect($host,$user,$pass); mysql_select_db($db,$this-db); /! An accessor /* * Fetches a query resources and stores it in a local member * param $sql string the database query to run * return void */ function fetch($sql) $this-query=mysql_unbuffered_query($sql,$this-db); / Perform query here /! An accessor /* * Returns an associative array of a query row * return mixed */ function getRow () if ( $row=mysql_fetch_array($this-query,MYSQL_ASSOC) ) return $row; else return false; ?在它上边放上模型。dao=& $dao; /! A manipulator /* * Tells the $dboject to store this query as a resource * param $start the row to start from * param $rows the number of rows to fetch * return void */ function listProducts($start=1,$rows=50) $this-dao-fetch(SELECT * FROM products LIMIT .$start., .$rows); /! A manipulator /* * Tells the $dboject to store this query as a resource * param $id a primary key for a row * return void */ function listProduct($id) $this-dao-fetch(SELECT * FROM products WHERE PRODUCTID=.$id.); /! A manipulator /* * Fetches a product as an associative array from the $dbobject * return mixed */ function getProduct() if ( $product=$this-dao-getRow() ) return $product; else return false; ?有一点要注意的是,在模型和数据访问类之间,它们的交互从不会多于一行?没有多行被传送,那样会很快使程式慢下来。同样的程式对于使用模式的类,它只需要在内存中保留一行(Row)?其他的交给已保存的查询资源(query resource)?换句话说,我们让MYSQL替我们保持结果。接下来是视图?我去掉了HTML以节省空间,你可以查看这篇文章的完整代码。model=& $model; /! A manipulator /* * Builds the top of an HTML page * return void */ function header () /! A manipulator /* * Builds the bottom of an HTML page * return void */ function footer () /! A manipulator /* * Displays a single product * return void */ function productItem($id=1) $this-model-listProduct($id); while ( $product=$this-model-getProduct() ) / Bind d
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 兵哥哥正能量课件
- 八月安全生产培训课件
- 河南信用修复管理办法
- 八国联军侵华课件
- 八十八天环游地球课件
- 动画技术在游戏制作中的应用研究-洞察及研究
- 个性化曲库生成策略-洞察及研究
- 傣族风情课件
- 退伙协议范本:有限责任公司股权退出操作细则
- 文化娱乐经销商空白合同领用与内容审核协议
- 灭火和应急疏散预案演练制度(足浴会所)
- 中国黄金集团招聘面试经典题及答案
- GB/T 4026-2025人机界面标志标识的基本和安全规则设备端子、导体终端和导体的标识
- 青岛版科学一年级上册(新教材)1.1 吹泡泡(教学课件)(内嵌视频)
- 感染性心内膜炎术后护理查房
- 推理能力题目及答案
- 2025年高等教育心理学模拟题(含答案)
- 2025年部编版新教材语文七年级上册教学计划(含进度表)
- 2025中国移动贵州公司秋季校园招聘笔试参考题库附带答案详解(10套)
- 医院科研奖励管理办法
- 上汽大众产品与业务培训
评论
0/150
提交评论