已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第三章 单例模式和工厂模式/模式就像是OOP开发人员的配方,每种模式都提供了所需的成分。我们可以自定义6A21式的元素来解决特定的编程问题。 模式对OOP开发人员尤其有用,因为它有助于创建稳定的API,并且仍然保持一定的灵活度。一种模式可以帮助我们定义负责完成特定任务的对象,还可以允许我们全部修改掉某个类而不用修改与这个类打交道的代码。前者被称为类的职责,后者被称为类的多态性。你也许已经在理论上学过这些概念,但本章将帮助你理解在应用程序中实现这些模式所需的PHP语法。 本章将介绍两种常用的模式:单例模式和工厂模式。单例模式被当作职责模式,它用来在应用程序中创建一个单一的功能访问点。工厂模式在多态性设计中非常重要。如果应用得当,工厂模式可以使得应用程序的移植性更好,类之间的依赖更松散,从而提高了灵活性。例如,通过工厂模式实现的多态性,我们就可以用一个新的试验性的类替换一个已经创建好的类,从而用一种安全稳定的方法来测试新的特性。3.1 职责和单例模式 在OOP中,一个对象只负责一个特定的任务通常是一种很好的做法。例如,你也许希望只让一个对象去访问数据库。单例模式被认为是职责模式,这是因为它将创建对象的控制权委托到一个单一的访问点上。在任何时候,应用程序中都只会有这个类仅有的一个实例存在。这可以防止我们去打开数据库的多个连接或者不必要地使用多余的系统资源。在更加复杂的系统中,使用单例模式在维持应用程序状态的同步方面也尤其有用。 所有的单例类至少拥有以下三种公共元素。 它们必须拥有一个构造函数,并且必须被标记为private。 它们拥有一个保存类的实例的静态成员变量。 它们拥有一个访问这个实例的公共的静态方法。 和普通类不同的是,单例类不能在其他类中直接实例化。单例类只能被其自身实例化。要获得这种限制效果,_construct()方法必须被标记为private。如果试图用private构造函数构造一个类,就会得到一个可访问性级别的错误。 要让单例类起作用,就必须使其为其他类提供一个实例,用它调用各种方法。单例类不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。结果是单例类不会重复占用内存和系统资源,从而让应用程序的其他部分更好地使用这些资源。作为这一模式的一部分,必须创建一个空的私有的_clone()方法,以防止对象被复制或者克隆。 返回实例引用的这个方法通常被命名为getInstance()。这个方法必须是静态的,而且如果它还没有实例化,就必须进行实例化。getInstance()方法通过使用instanceof操作符和self关键字,可以检测到类是否已经初始化。如果保存实例的静态成员为空或者还不是类自身的一个实例,那么这个实例将会被创建并保存到存放实例的变量中。 代码清单3-1显示了用来封装数据库连接对象的一个单例类的例子。代码清单3-1 数据库连接职责的集中控制 class Database private $_db; static $_instance; private function _construct() $this-_db = pg_connect(dbname=example_db); private _clone(); public static function getInstance() if(!(self:$_instance instanceof self) self:$_instance = new self(); return self:$_instance; public function query($sql) /使用$this-_db执行一个查询 return pg_query($this-_db,$sql); 这个例子一开始声明了两个变量:一个实例变量$_db,构造对象时这个变量的值会被填充;另外一个是静态变量$_instance,这个变量会保存类仅有的一个实例。 接着是私有的_construct()和_clone()魔术方法。私有构造函数可以防止外部代码使用new操作符来创建对象。类似地,私有的_clone()方法消除了PHP语言中可以复制对象从而破坏单一职责的一个漏洞。 这之后的代码声明了getInstance()静态方法。这是单例模式的实际构造。这个函数会检查静态实例变量是否已保存这个类的一个实例。如果它没有包含自身的一个实例,类会被初始化并且保存到$_instance变量中。下一次调用这段代码时,$_instance变量会保存类的一个实例,并且这个类不会再次实例化。最后,这个方法会返回实例的引用。现在,你已经看到了如何生命单例类。但是应该如何使用它那?代码清单3-2演示了从另外一个场景中使用单例类的做法。代码清单3-2使用单例类$db = Database:getInstance();$db -query(SELECT * FROM example_table);通过调用getInstance()方法,$db现在存有内部存储实例的引用。通过这个实例,你可以调用单例类中定义的任何非静态方法。如果某个类不需要使用_construct方法,那么这个类就不太适合使用单例模式。在这种情况下,应该使用纯静态类。你只需要提供一个没有函数体的私有构造函数,并且去掉getInstance()和$_instance成员就可以做到这一点。这会防止类被实例化,它通过消除使用这段代码时获得实例的可能性确保了单一职责性。代码清单3-3显示了纯静态类的一个例子。代码清单3-3使用不能被实例化的纯静态类class SomeClass/防止类被当做实例使用private function _construct() public static function SomeMethod()/执行一些操作3.2工厂模式工厂类是指包含了一个专门用来创建其他对象的方法的类。工厂类在多态性编程实践中是至关重要的。它允许动态地替换类,修改配置,并且通常会使应用程序更加灵活。熟练掌握工厂模式对高级PHP开发人员来说是很重要的。工厂模式通常用来返回符合类似接口的不同的类。工厂的一种常见用法就是创建多态的提供者,从而允许我们基于应用程序逻辑或者配置设置来决定应该实例化哪一个类。例如,可以使用这样的提供者来扩展一个类,而不需要重构应用程序的其他部分,从而使用新的扩展后的名称。通常,工厂模式有一个关键的构造,即根据一般的原则被命名为factory的静态方法。然而,这只是一种原则,工厂方法可以任意命名。这个静态方法还可以接受任意数量的参数,并且必须返回一个对象。代码清单3-4演示了经常会用到的一种最基本的工厂类。代码清单3-4创建一个基本的工厂类class MyObject /对象将从工厂类返回class MyFactorypublic static function factory()/返回对象的一个新实例return new MyObject();然后,我们可以用以下代码调用工厂。$instance = Myfactory : factory();但是,这个类实际上没有任何用处。下面来看一些实际场景下可能会用到工厂的例子。3.2.1图像对象工厂这是一个名为Picture 的绘图程序。你希望能够将包含在某个文件中的图像绘制到屏幕上。不同的图像文件具有完全不同的文件格式,将每种可能碰到的图像类型的图像解析代码全部放到一个类中是不合适的。在这种情况下,需要为每种图像类型创建一个类,比如Image_PNG、Image_JPEG等。每个类应该包含在一个单独的文件中。所有这些图像类都应该包含几个公共的方法以获取图像的高度、宽度和原始图像数据。然而,它们解析对应文件以获取这些信息的方法完全不同。你可以使用一个接口来定义公共功能,并创建一个工厂模式以使得API更加容易使用,如代码清单3-5所示。代码清单3-5使用工厂类解析图像文件interface IImagefunction getWidth();function getHeight();function getData();class Image_PNG implements IImageprivate $_width , $_height , $_data;public function _construct($file)$this - _file = $file;$this - parse();private function _parse()/完成PNG格式的解析工作/并填充$_width、$_height 和 $_datapublic function getWidth()return $this-_width;public function getHeight()return $this-_height;public function getData()return $this-_data;class Image_JPEG implements IImageprivate $_width,$_height,$_data;public function _construct($file)$this - _file = $file;$this - _parse();private function _parse()/完成JPEG格式的解析工作/并填充$_width、$_height 和 $_datapublic function getWidth()return $this-_width;public function getHeight()return $this-_height;public function getData()return $this-_data;class ImageFactorypublic static function factory($file)$pathParts = pathinfo($file);switch(strtolower($pathPartsextension)case jpg:$ret = new Image_JPEG($file);break;case png:$ret = new Image_PNG($file);break;default:/有问题if($ret instanceof IImage)return $ret; else /有问题现在当使用图像文件名调用工厂方法时,根据传入的文件类型的不同,你将获得不同的对象。既然所有的Image_*类都实现了IImage接口,那么就可以在返回的实例上使用一套一致的方法调用。$image = ImageFactory : factory(/path/to/my.jpg);/$image 现在是Image_JPEG的一个实例echo $image -getWidth();在这个例子中,ImageFactory是工厂类,因为它返回了一个类的实例。类的类型是通过调用pathinfo()函数获得的文件扩展名来决定的。由于它是一个工厂类,产生的应用程序不需要知道这些图像解析的细节,需要知道的是工厂返回的对象支持IImage接口。使用这一技术使得API更加容易调用,这是因为它只有一个类和一个方法。如果不使用工厂模式,API的调用者将需要决定应该调用的类,然后去调用某个特定的类,这样就需要对工厂的行为进行复制。使用工厂模式还使得未来对应用程序做出改变更加容易。添加另外一种支持的图像类型只需要修改一个工厂方法即可。没有工厂模式,则需要更新调用API的所有代码块。在下一个例子中,我们将更加深入的解析通常被称为未来校验的概念。3.2.2可移植的数据库在PHP 应用程序中,通常会使用关系型数据库来存储应用程序创建和引用的数据。使用数据库的一个最大的问题就是不能用一种可移植并且可互换的方法与它们打交道。如果将某个应用程序的数据库移植到另外一种数据库上,可能需要重构大部分的代码,这是因为在开发应用程序时,没有考虑发生这种变化的可能性。在使用数据库的应用程序中,工厂模式可以在以下两个方面起作用。 使软件更容易支持各种不同的数据库平台,这一特性将有助于扩充用户群。如果软件是内部使用软件,那么在需要修改数据库时,便可以很容易地将应用程序移植到另外一个平台。代码清单3-6演示了使用数据库工厂的概念。你也希望创建一个名为user的数据库表来测试它,这个表应该定义一个名为email的varchar类型的字段。代码清单3-6 使用工厂类解决数据库可移植性问题interface IDatabaseBindings public function userExists($email);class PGSQL implements IDatabaseBindings protected $_connection; public function _construct() $this-_connection = pg_connect(dbname=example_db); public function userExists($email) $emailEscaped = pg_escape_string($email); $query = select 1 from users where email = . $emailEscaped .; if($result = pg_query($query,$this-_connection) return (pg_num_rows($result)0)?true:false; else return false; class MYSQL implements IDatabaseBindings protected $_connection; public function _construct() $this-_connection = mysql_connect(localhost); mysql_select_db(example_db,$this-_connection); public function userExists($email) $emailEscaped = mysql_real_escape_string($email); $query = select 1 from users where email = . $emailEscaped .; if($result = mysql_query($query,$this-_connection) return (mysql_num_rows($result)0)?true:false; else return false; class DataBaseFactory public static function factory() $type = loadtypefromconfigfile(); switch($type) case PGSQL: return new PGSQL(); break; case MYSQL: return new MYSQL(); break; /- 用法 -$db = DatebaseFac
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年社会救助政策实务试题及答案
- 市政井盖异响快速处置方案
- 2027届山东省济宁市鲁桥镇第一中学九年级化学第一学期期中学业质量监测模拟试题含解析
- 2026职业指导师岗位试题库及答案
- 有机化学复试面试常考题目及答案
- 进场砂石料分区堆放方案
- 中小学劳动素养评价实施细则
- 2026年老年痴呆患者照护试题(附答案)
- 2026年资产评估成本法运用试题(附答案)
- 2026年事业单位公共基础知识考试题(附答案)
- 应急管理执法考试题库(附答案)
- 创维电视机49E360E使用说明书
- 爱情合同协议书搞笑
- 眼科学角膜病试题及答案
- T∕CACM 010-2017 中医药单用联合抗生素治疗常见感染性疾病临床实践指南 盆腔炎性疾病
- 《物联网基础知识》课件
- 2024年国家大剧院公开招聘专业技术及一般管理人员33人历年高频500题难、易错点模拟试题附带答案详解
- 2024年秋季1530安全教育记录
- 小孩办身份证的委托书范本
- DL-T5704-2014火力发电厂热力设备及管道保温防腐施工质量验收规程
- pvc地胶施工工艺演示
评论
0/150
提交评论