什么是单例模式?先来看一下维基百科的解释:单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
概念理解起来可能比较困难,用最简单的话来概括单例模式就是,在创建一个类的时候,通过某种方法,来保证这个类只能产生一个实例。这么做有什么好处呢?我们知道,当我们编写好一个类之后,要产生这个类的实例是非常简单的,直接用new关键字就可以,那么,在一些大型的项目当中,同一个页面可能不是一个人开发,例如有一个Mysql的类,第一个开发人员实例化一个mysql对象,第二人去开发的时候,可能又去实例化了一个db对象,这两个对象其实都是一样的,每次实例化一个对象的时候,可能都需要去连接一次数据库,这样是非常浪费系统资源的。单例模式的出现就是为了避免对一个类的重复实例化问题的产生,从而节省资源。
首先来看一下PHP中怎么实现单例模式,我们知道,当用new实例化一个对象的时候,对象都有一个__construct的方法自动被调用,那么,我能不能把这个方法设为私有或者保护起来,从而不让new产生对象呢?来看下面这个例子:
<?php class Human{ static protected $obj=NULL; //定义类的静态属性 final protected function __construct(){ //定义类的__construct函数为不能被子类改写的,不能被自动调用的空方法 } static public function getInstance(){//定义类的静态方法,用来获取对象 if(self::$obj instanceof self){ return self::$obj; }else{ self::$obj=new self; return self::$obj; } } final protected function __clone(){//定义类的clone方法,保证实例化的对象不能被克隆 } public function say(){//公共方法 echo "Hello"; } } class Stu extends Human{ public $name="Hito"; } $a1=Human::getInstance(); $a2=Human::getInstance(); $a3=Stu::getInstance(); if($a1===$a2&&$a2===$a3){ echo "对象相同"; }else{ echo "对象不相同"; } $b1=new Human();//错误:Call to protected Human::__construct() from invalid context $b2=new Stu();//错误:Call to protected Human::__construct() from invalid context $a4=clone $a3;//Fatal error: Call to protected Human::__clone() from context '' $a3->name;//Undefined property: Human::$name ?>
原理是这样的:首先定义Human的一个受保护的静态属性,这个属性用来存放返回的对象(初始化为空);定义类的__construct方法为final和protected,final保证继承自Human的自对象不能改写__contruct方法,protected保证外部不能调用__construct,这样,就不能通过new来产生实例化Human的对象了;第三,定义一个静态的公共方法getInstance来获取对象,为了保证多次获取的对象都是同一个对象,把最终产生的对象赋给了Human的静态属性$obj,判断如果$obj是实例化的Human,则返回$obj,如果不是,把产生一个实例化的Human对象,然后赋值给$obj,再返回$obj。这样,就保证了多次请求返回的是同一个对象;第四,定义不能被改写的__clone魔术方法,防止实例化的对象被克隆,从而产生一个不同的对象;最后一个是共有的方法。
可以看到Stu这个类是继承于Human的,但是实际上却返回的是Human实例化的对象,也就是说我在class Stu extends Human中定义一个公共的非静态的方法或者属性,$a3是不能访问的,在上面代码的倒数第二行可以看到。
总结PHP单例模式的特点:
1,通过定义类的构造函数为私有或受保护来防止用new实例化;
2,通过final关键字保证相关属性或方法不能被子类改写;
3,通过定义魔术方法,保证对象不能被克隆
4,设置一个类的公共静态方法来产生实例化的对象,并把实例化之后的对象赋值给这个类的一个静态属性,以后每次请求产生对象,都返回这个静态属性指向的对象。
那么,在Javascript中,单例模式是什么样的呢?从上面的概念可以看出,单例模式就是为了避免类的重复实例化导致资源的浪费,实际在Javascript中,除开我们自定义的function类,其它对象字面量都是不能被实例化的,因为它们本身不是构造函数。一个简单的单例模式:
<script> var Human={Name:"Hito",Age:25} //或者通过函数返回对象: var Human=(function(){ var Name="Hito"; var Age=25; return { Name:Name, Age:Age } } )() var xiaoming=mew Human();//Uncaught TypeError: object is not a function </script>
在上面的例子中,我们不能通过new来创建一个新的对象。这两种方法虽然实现了JS的单例模式,可以我并没有像PHP那样直接屏蔽掉类的new方法,我们来看最后一种实现方法:
<script> function Human(){ if(Human.instance){ return Human.instance; } this.name="Hito"; this.Age=25; Human.instance=this; } var a1=new Human(); var a2=new Human(); alert(a1===a2);//true </script>
在这个例子中,定义一个Human类,Human类有个属性instance,如果存在的话,直接返回这个属性,如果不存在,那么则设置相应的属性。使用数据缓存来存储该单例,用作判断单例是否已经生成,是这种方法主要的实现思路。
评论列表: