php 常见的设计模式(PHP中常用的三种设计模式详解单例模式、工厂模式、观察者模式)
php 常见的设计模式
PHP中常用的三种设计模式详解单例模式、工厂模式、观察者模式本文实例讲述了PHP中常用的三种设计模式。分享给大家供大家参考,具体如下:
PHP中常用的三种设计模式:单例模式、工厂模式、观察者模式
1.单例模式
为何要使用PHP单例模式?
多数人都是从单例模式的字面上的意思来理解它的用途, 认为这是对系统资源的节省, 可以避免重复实例化, 是一种”计划生育”. 而PHP每次执行完页面都是会从内存中清理掉所有的资源. 因而PHP中的单例实际每次运行都是需要重新实例化的, 这样就失去了单例重复实例化的意义了. 单单从这个方面来说, PHP的单例的确有点让各位失望. 但是单例仅仅只有这个功能和应用吗? 答案是否定的。
- php的应用主要在于数据库应用, 所以一个应用中会存在大量的数据库操作, 在使用面向对象的方式开发时(废话), 如果使用单例模式, 则可以避免大量的new 操作消耗的资源。
- 如果系统中需要有一个类来全局控制某些配置信息, 那么使用单例模式可以很方便的实现. 这个可以参看zend Framework的FrontController部分。
- 在一次页面请求中, 便于进行调试, 因为所有的代码(例如数据库操作类db)都集中在一个类中, 我们可以在类中设置钩子, 输出日志,从而避免到处var_dump, echo。
一个单例类应包括以下几点:
和普通类不同,单例类不能被直接实例化,只能是由自身实例化。因此,要获得这样的限制效果,构造函数必须标记为private。
要让单例类不被直接实例化而能起到作用,就必须为其提供这样的一个实例。因此,就必须要让单例类拥有一个能保存类的实例的私有静态成员变量和对应的一个能访问到实例的公共静态方法。
在PHP中,为防止对单例类对象的克隆来打破单例类的上述实现形式,通常还为其提供一个空的私有__clone()
方法。
对于一个类的对象,如果使用“clone运算符”,就会复制出一个和当前对象完全一样的新对象出来,并且,此时还会自动调用该类的魔术方法:__clone()
(只要该类中有该方法)。
则要实现单例类,就应该对这个单例类的对象“禁止克隆”,用private来修饰__clone()来实现禁止克隆,具体可参考单例类的加强:禁止克隆。
单例模式的例子:
|
<?php /** * 设计模式之单例模式 * $instance必须声明为静态的私有变量 * 构造函数和析构函数必须声明为私有,防止外部程序new * 类从而失去单例模式的意义 * getInstance()方法必须设置为公有的,必须调用此方法 * 以返回实例的一个引用 * ::操作符只能访问静态变量和静态函数 * new对象都会消耗内存 * 使用场景:最常用的地方是数据库连接。 * 使用单例模式生成一个对象后, * 该对象可以被其它众多对象所使用。 */ class SingetonBasic { private static $instance ; //静态变量要私有化,防止类外修改 // other vars.. private function __construct() { //构造函数私有化,类外不能直接新建对象 // do construct.. } private function __clone() {} //在__clone()前用private修饰,用来禁止克隆 public static function getInstance() { //公共的静态方法,public——外部的接口,static——不使用对象而是通过类名访问 if (!(self:: $instance instanceof self)) { //私有静态变量$instance为空 self:: $instance = new self(); //新建为自身的对象,并赋值给私有变量$instance } return self:: $instance ; //返回私有变量$instance } // other functions.. } $a = SingetonBasic::getInstance(); $b = SingetonBasic::getInstance(); var_dump( $a === $b ); //结果为:boolean true //?> |
|
<?php /** * php单例,单例模式为何只能实例化一次 */ class Example{ // 保存类实例在此属性中 private static $instance ; // 构造方法声明为private,防止直接创建对象 private function __construct(){ echo 'I am constructed' ; } // singleton 方法 public static function singleton(){ if (!isset(self:: $instance )) { //判断是否以前创建了当前类的实例 $c = __CLASS__ ; //获取类名 self:: $instance = new $c ; //如果没有创建,实例化当前类,这里实现类只实例化一次 } return self:: $instance ; //返回类的实例 } // Example类中的普通方法 public function bark(){ echo 'Woof!' ; } // 阻止用户复制对象实例 public function __clone(){ trigger_error( 'Clone is not allowed.' , E_USER_ERROR); } } // 这个写法会出错,因为构造方法被声明为private $test = new Example; // 下面将得到Example类的单例对象 $test = Example::singleton(); $test ->bark(); // 下面将得到Example类的单例对象 $test = Example::singleton(); $test ->bark(); // 复制对象将导致一个E_USER_ERROR. $test_clone = clone $test ; ?> |
关于__clone()
方法可参考: PHP对象克隆__clone()介绍
2. 工厂模式
工厂模式在于可以根据输入参数或者应用程序配置的不同来创建一种专门用来实现化并返回其它类的实例的类。
工厂模式的例子:
|
<?php class FactoryBasic { public static function create( $config ) { } } |
比如这里是一个描述形状对象的工厂,它希望根据传入的参数个数不同来创建不同的形状。
|
<?php // 定义形状的公共功能:获取周长和面积。 interface IShape { function getCircum(); function getArea(); } // 定义矩形类 class Rectangle implements IShape { private $width , $height ; public function __construct( $width , $height ) { $this ->width = $width ; $this ->height = $height ; } public function getCircum() { return 2 * ( $this ->width + $this ->height); } public function getArea() { return $this ->width * $this ->height; } } // 定义圆类 class Circle implements IShape { private $radii ; public function __construct( $radii ) { $this ->radii = $radii ; } public function getCircum() { return 2 * M_PI * $this ->radii; } public function getArea() { return M_PI * pow( $this ->radii, 2); } } // 根据传入的参数个数不同来创建不同的形状。 class FactoryShape { public static function create() { switch (func_num_args()) { case 1: return new Circle(func_get_arg(0)); break ; case 2: return new Rectangle(func_get_arg(0), func_get_arg(1)); break ; } } } // 矩形对象 $c = FactoryShape::create(4, 2); var_dump( $c ->getArea()); // 圆对象 $o = FactoryShape::create(2); var_dump( $o ->getArea()); |
使用工厂模式使得在调用方法时变得更容易,因为它只有一个类和一个方法,若没有使用工厂模式,则要在调用时决定应该调用哪个类和哪个方法;使用工厂模式还使得未来对应用程序做改变时更加容易,比如要增加一种形状的支持,只需要修改工厂类中的create()一个方法,而没有使用工厂模式,则要修改调用形状的代码块。
3. 观察者模式
观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。
一个简单的示例:当听众在收听电台时(即电台加入一个新听众),它将发送出一条提示消息,通过发送消息的日志观察者可以观察这些消息。
|
<?php // 观察者接口 interface IObserver { function onListen( $sender , $args ); function getName(); } // 可被观察接口 interface IObservable { function addObserver( $observer ); function removeObserver( $observer_name ); } // 观察者类 abstract class Observer implements IObserver { protected $name ; public function getName() { return $this ->name; } } // 可被观察类 class Observable implements IObservable { protected $observers = array (); public function addObserver( $observer ) { if (!( $observer instanceof IObserver)) { return ; } $this ->observers[] = $observer ; } public function removeObserver( $observer_name ) { foreach ( $this ->observers as $index => $observer ) { if ( $observer ->getName() === $observer_name ) { array_splice ( $this ->observers, $index , 1); return ; } } } } // 模拟一个可以被观察的类:RadioStation class RadioStation extends Observable { public function addListener( $listener ) { foreach ( $this ->observers as $observer ) { $observer ->onListen( $this , $listener ); } } } // 模拟一个观察者类 class RadioStationLogger extends Observer { protected $name = 'logger' ; public function onListen( $sender , $args ) { echo $args , ' join the radiostation.<br/>' ; } } // 模拟另外一个观察者类 class OtherObserver extends Observer { protected $name = 'other' ; public function onListen( $sender , $args ) { echo 'other observer..<br/>' ; } } $rs = new RadioStation(); // 注入观察者 $rs ->addObserver( new RadioStationLogger()); $rs ->addObserver( new OtherObserver()); // 移除观察者 $rs ->removeObserver( 'other' ); // 可以看到观察到的信息 $rs ->addListener( 'cctv' ); ?> |
希望本文所述对大家PHP程序设计有所帮助。
原文链接:https://blog.csdn.net/Yeoman92/article/details/52809661
- php中类的属性含义(php类中static与self的使用区别浅析)
- php可以一次下载几个文件(php实现大文件断点续传下载实例代码)
- php时间戳是什么意思(php时间戳转换代码详解)
- thinkphp分页效果怎样(thinkphp5+layui实现的分页样式示例)
- php语法检测方法(php中文语义分析实现方法示例)
- php抽象入门教程(php抽象方法和普通方法的区别点总结)
- php开发的主要技术(详解PHP神奇又有用的Trait)
- phpsession怎么用(PHP实现提高SESSION响应速度的几种方法详解)
- php闰年计算公式(php判断/计算闰年的方法小结三种方法)
- php根据名称规则判断文件是否存在(PHP中上传文件打印错误错误类型分析)
- php面向对象运用场景(PHP面向对象类型约束用法分析)
- php数据错误处理函数(php中错误处理操作实例分析)
- phpstudy怎么升级mysql(phpStudy中升级MySQL版本到5.7.17的方法步骤)
- php怎么设置curl(php curl发送请求实例方法)
- php全栈之路教程(PHP进阶学习之依赖注入与Ioc容器详解)
- php中字符串反转的函数(php常用字符串查找函数strstr与strpos实例分析)
- 刚红就耍大牌,《琉璃》角色滤镜碎一地,心疼工作人员(琉璃角色滤镜碎一地)
- 袁冰妍郑业成这对可以处,有脸红情话他们是真的敢说(袁冰妍郑业成这对可以处)
- 《祝卿好》台词又土又甜,就喜欢这么直接的恋爱(祝卿好台词又土又甜)
- 大女主 汤唯垂青电视圈,搭档朱亚文出演《大明皇妃孙若微传》(汤唯垂青电视圈)
- 红色代表什么(红色代表什么情感和含义)
- 高中数学题(高中数学题型总结及解题方法)
热门推荐
- 微信js开发教程(微信JSSDK分享功能图文实例详解)
- sql中row的用法(sql server数据库中raiserror函数用法的详细介绍)
- MYSQL字符集设置的方法详解(终端的字符集)(MYSQL字符集设置的方法详解终端的字符集)
- laravel数据绑定(laravel-admin表单提交隐藏一些数据,回调时获取数据的方法)
- sqlserver游标实例(Sql Server临时表和游标的使用小结)
- linq distinct去重
- phpstudy的mysql无法启动(Windows系统下解决PhPStudy MySQL启动失败问题)
- 阿里云服务器内外网址(阿里云服务器网站发现后门该怎么处理)
- server2008对前端有啥用(MyWebServer好不好?MyWebServer WEB服务器软件介绍)
- Ext.MessageBox.show()的用法及参数配置
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9