PHP中的设计模式:单例模式(译)
原文链接:http://coderoncode.com/2014/01/27/design-patterns-php-singletons.html
单例模式用于限制类实例化到单个对象,当整个系统只需要一个对象时这将有用。
单例模式被设计来确保只有一个单一的(因此得名单例)类实例,并且有一个全局的访问点。通过这个单一实例我们有一个全局的访问点并且可以延迟初始化。
一个基本的单例实现看起来像下面的例子:
<?php
/** Example taken from http://www.webgeekly.com/tutorials/php/how-to-create-a-singleton-class-in-php/ **/
class User
{
// Hold an instance of the class
private static $instance;
// The singleton method
public static function singleton()
{
if (!isset(self::$instance)) {
self::$instance = new __CLASS__;
}
return self::$instance;
}
}
$user1 = User::singleton();
$user2 = User::singleton();
$user3 = User::singleton();
?>
在上面的例子中3个变量都指向同一个对象。第一次调用会实例化出一个对象,而后续的调用都只返回该对象。
“在计算机编程中,延迟初始化是一种策略,直到第一次需要时才会去创建一个对象、计算一个值或者其他昂贵的过程。”
让我们看看显而易见而又被忽略的事实,并且讲讲为什么单例模式被许多开发者认为是一种“反模式”,尽管这么讲要高度依赖于所使用的框架和语言,然而PHP中的单例模式几乎被普遍认为是一种“反模式”。
“单例模式被许多人认为是一种反模式,反模式是一种解决方案,但是这种解决方案往往是无效的,甚至会带来高风险的反作用。”
单例模式是来自地狱的卵?
如果你之前读到过单例模式,你可能想知道到底我在表达什么?
单例模式是邪恶的,是一种“反模式”,并且绝不能使用它。光说单例模式是邪恶的还仅仅不够,我们需要知道为什么需要避免使用单例模式,这正是我想在这篇文章中阐明的。
单例模式被认为是一种“反模式”有几个原因,让我们来看看其中的一些原因:
单一职责模式
我们使用单一模式所面对的第一个问题便是:它的使用打破了单一职责原则。
单例对象有着用途和控制生产出的实例数量这两个职责,而单一职责原则则指出:每个类应该只有一个职责,并且这个职责应该由类来完全封装。
隐藏的依赖关系
什么是隐藏的依赖关系,以及这和单例模式是如何有关的?如果你看过我之前的有关依赖注入的文章,我们看到了如何把依赖关系通过参数传递给函数。
一个函数接收到的任何参数称为可见的依赖。另一方面,如果一个函数需要一个类似全局变量的东西(读取单例)来运作,那么这种依赖被认为是隐藏的。
这表明,如果不去看实际函数的实现的话,那么第三方是没有办法知道这个隐藏的依赖关系的。
“一个可见的依赖是一种开发者可以从类的接口看见到的依赖。如果一个依赖不能从类的接口看见的话,那么这个依赖就是一个隐藏的依赖”—jenkov.com
测试
伴随着这些问题,当我们对我们的应用程序进行单元测试是会有一个问题。合适的单元测试应该能像数据库那样独立地运行。单例模式让单元测试即使不是不可能的也会是困难的,因为单例模式有一个全局的状态。
这意味着,一旦实例化,那么这个实例便会仅仅围绕着这个单元测试。这可能会导致测试中意外地相互影响。
有个变通方法,那就是每次测试运行后好好地“清理”单例,然而我发现这仍然是生产上的禁忌并且很麻烦。
并不全是坏事,不是吗?
它们不能全是坏事,不是吗?好吧,让我们试着辩论下单例模式的好处和某些情况下它们是有用的:
1、调试日志:几乎所有的开发者都同意调试日志记录这种方式应该适用于每一个功能和每一部分的代码。单例模式可以在不伤害可读性、可测试性及可维护性上达到这个目的。
2、文件系统和数据库访问:访问文件系统和数据库用单例模式是由理由的,如果你需要一个文件系统或者数据库的全局访问点,单例模式在提供灵活性和可测试性上会小有帮助,这是有用的。
结论
单例模式、“反模式”和设计模式一般来讲并不是好的或者坏的。是什么让单例模式变成一个“反模式”并不是因为模式本身,而是因为单例模式往往很容易地被人们很差地实现。
如果被不正确地实现(这是经常发生的),任何模式都可能变成“反模式”。话虽这么说,就现代的PHP和现代的框架来说很难有赞成单例模式的情况。就我个人而言,对于单例模式,我看不出它有什么好处,恰恰看到了它有许多的缺点。
最后我明白的一点是,单例模式是一个有争议和偏见的话题。如果你有想补充任何在这篇文章中提到的观点,或者能提供有用的案例,我非常想看到你们在文章后面的评论。
更多文章请关注我的个人博客:http://www.nomoneynowife.com
PHP中的设计模式:单例模式(译)的更多相关文章
- [工作中的设计模式]单例模式singleton
一.模式解析: 单例模式是最简单和最常用的设计模式,面试的时候,不管新毕业的学生还是已经工作多年的筒子,对单例模式基本都能聊上两句.单例模式主要体现在如下方面: 1.类的构造函数私有化,保证外部不能直 ...
- 7.JAVA基础复习——JAVA中的设计模式单例模式
设计模式:是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 总体来说设计模式分为23种三大类: 创建型模式,共 ...
- .net中的设计模式---单例模式
.net设计模式: Net设计模式实例之单例模式( Singleton Pattern) 一 : 单例模式的简介:(Brief Introduction) 单例模式(Singleton Patter ...
- .net中的设计模式---单例模式,涉及lock的用法
.客户端代码 static void Main(string[] args) { Singleton singleton2 = Singleton.GetInstance(); Singleton s ...
- Django中settings设计模式(单例模式)
配置文件: 需求:配置文件,默认配置和手动配置分开,参考django的配置文件方案,默认配置文件放在项目容器内部,只让用户做常用配置. /bin/settings.py(手动配置) PLUGIN_IT ...
- JavaScript 中常见设计模式整理
开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式.本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知. JavaScript 中常见设计模 ...
- JS中常见设计模式总结
github: https://github.com/14glwu/FEInterviewBox/tree/master/JS%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F ...
- [Head First设计模式]抢票中的设计模式——代理模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- [Head First设计模式]餐馆中的设计模式——命令模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- Spring中的设计模式
[Spring中的设计模式] http://www.uml.org.cn/j2ee/201301074.asp [详解设计模式在Spring中的应用] [http://www.geek521.c ...
随机推荐
- n维立体空间建模
n维立体空间建模,基于网格技术,将整个地球信息整体封装,初始进行网格化,选取某一个网格,进行迭代, 迭代的子项依然是网格,迭代的次数为k,网格最终大小可以指定,这种指定决定了立体块的细化率,假设 ...
- List迭代循环时出现分问题
一个List,通过迭代之后给List中的实体重新赋值,代码如下 public List getListByPage(Page currPage) { Map recordTypeMap = BusnD ...
- (DT系列二)device tree的书写规范
devicetree的书写规范 下面从节点,属性,reg,ranges,中断控制器等几个方面叙述devicetree的书写规范. 1,dts的基本元素:节点 .dts(或者其include的.dtsi ...
- (DT系列一)DTS结构及其编译方法
DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 3,dts是如何被编译的,以及编译后会生成一个什么文件. 二:参考文字 1,DTS(device tre ...
- Java内存区域 - 深入Java虚拟机读后总结
Java虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,有各自的创建时间和销毁时间,有的区域随着虚拟机进程的启动而存在,有的区域则是依赖用户线程的启动 ...
- 在JSP页面中调用另一个JSP页面中的变量
在jsp学习中,经常需要在一个jsp页面中调用另一个jsp页面中的变量,下面就这几天的学习,总结一下. jsp页面之间的变量调用有多种方法: 1.通过jsp的内置对象—request对象获取参数: ( ...
- JavaScript实现遮罩层
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- ubuntu 14.04 chromium,firefox 怎样正确安装Adobe flash player
一.firefox 正确安装Adobe flash player 有时候我们须要在Ubuntu下採用手动安装一些软件,比方Firefox的Flash插件.Adobe® Flash® Player 是一 ...
- PowerMock注解PowerMockIgnore的使用方法
故事要从一个异常开始,某天我在开发一个加密.解密特性,算法使用的是3DES,样例代码如下. package org.jackie.study.powermock; import java.io.Uns ...
- careercup-数组和字符串1.5
1.5 利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能.比如,字符串”aabcccccaaa“会变成”a2b1c5a3“.若”压缩“后的字符串没有变短,则返回原先的字符串. 类似 le ...