开发者学堂课程【PHP 进阶教程-由浅入深掌握面向对象开发-第三阶段:单例模式】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/713/detail/12719
单例模式
内容介绍:
一、目标
二、概念
三、步骤
四、示例
五、总结
一、目标
前面分析了对应的任务管理器只能出现一个,单例模式能够保证每次新建都只有一个,而第一次又能产生。
目标:理解单例模式的概念,掌握单例模式解决方案
二、概念
单例模式: singleton,是一种类的设计只会最多产生一个对象的设计思想(一个类在一次脚本运行的周期中最多产生一个对象)
·单例模式的类只能在一次运行中产生一个对象
·单例模式为了解决如何只产生一个对象,需要使用以下解决方案,简称三私一公:
私有化构造方法:不让在外部产生多个对象(实例化对象会去调用构造方法,在外面可以无限去实例化对象)
私有化克隆方法:不允许对象被克隆产生新对象
此时出现一个问题:任何产生对象的私有化,私有化需要回归本质是外部不能调用,内部可以调用,只要进入内部就可以实例化产生对象。
公有化静态方法:运行进入类内部产生对象
产生对象后的每一次都可以产生对象,所以需要把对象存起来,以后想要用就给出这个对象,只给一个就保证只有一个对象。
私有化静态属性:保存已经产生的对象
三、步骤
1、定义空类
2、杜绝能够产生多个对象的方式:构造方法私有化
3、想办法产生对象:进入类内部产生对象(私有化只能在类的内部访问)
4、想办法控制内部对象生产:只生产一个(产生过后保留,以后只拿现有的而不去产生新的)
5、杜绝外部拿着已有对象产生新对象:克隆方法私有化
四、示例
1、首先定义一个空类,叫做 Singleton
#创建一个空类
class singleton{
}
此时无法实现实例化,系统报错,所以无法通过这种方式来产生对象。
此时需要进入到类里来产生对象,采用静态方法
2、对象的产生是通过实例化产生的,而实例化是一种不可控行为,即可以产生无限多个对象,所以应该禁止,即"禁止实例化",之所以是引号,是因为只能禁止在类外部实例化对象,私有化构造方法
#在上述类中增加私有化构造方法
class singleton{
#私有化构造方法:防止外部无限实例化对象
private function __construct(){}
#没有初始化需求的话,构造方法可以为空方法
}
#尝试外部实例化
$s = new Singleton()
#致命错误:不能访问私有方法
new self 产生对象,然后把对象返回给外部,就可以拿到对象
但是此时每次都会实例化,如果再添加$2,就会得到一个新的对象。
这个时候还需要进行一些优化,来保证对象只实例化一次。如果发现已经产生了对象就不再 new 而是直接拿到原来的对象。
3、一旦外部不能实例化对象了,那就意味着根本"不可能’产生对象了,此时就只能想办法在还没有产生对象的时候就进入到“类内部",意味着只能通过静态方法让类直接进入到类的内部
#在上述类中增加公有静态方法
public static function getInstance(){
}
4、进入类的内部依然还是没有对象,此时需要在静态方法内部进行对象实例化,并且把得到的对象返回到外部
#修改公有静态方法:获取对象,并返回给外部调用出
public static function getInstance(){
return new self();
}
#外部获取对象
$s = singleton: :getInstance();
5、此方法开启了实例化对象的窗口,但是此时新问题出现:无限调用静态方法依然可以得到多个对象。如果想要该方法只返回一个对象,就得保证类内部有办法存着某个产生的对象,第一次产生新的,后面返回旧的。此时需要使用静态属性,静态属性把当前产生的放到里面,最后返回的是静态属性保存的对象。还要用 is_object 函数来判定是否是对象的 self,因为一开始没有值。instanceof 用来判断当前对象是不是指定类的对象,保证更精确。
#增加静态属性:私有,不允许外部修改,否则外部修改之后就没有意义了
private static $object = NULL;
#初始化为NULL,没有对象
#修改静态方法
#公有静态方法:产生对象返回给外部调用者
public static function getInstance(){
#判断内部属性是否存在对象(is_object函数):最好的判定是存的对象是当前类的 instanceof
#return new self();
#判定对象是否已经产生过
if(!self: : $object instanceof se1f)){
#当前保存的内容不是当前类的对象
#没有产生对象
self: : $object = new self();
}
#返回静态属性保存的对象即可
#返回对象给外部
return self: : $object;
}
# new Singleton();
#错误
$s1 = Singleton: :getInstance();
$s2 = singLeton: : getInstance();
var_dump($s1,$s2);
此时判定对象是否产生过,如果不是说明对象没有产生过。到这里就可以保证静态属性里一定有一个对象,如果是,if 不走,表示本身有对象,如果不是,需要实例化产生对象。此时返回静态属性保存的对象即可。调用这个方法n次产生的最终返回这一个对象,不会产生新的对象。
此时克隆还可以产生新的对象
此时需要私有化克隆方法,防止外部进行对象克隆。这时就可以保证类只会产生一个对象。
6、此时可以保证外部无论多少次调用公有静态方法获取实例,都会只得到一个对象。但是此时外部对象依然可以产生新的对象:因为克隆,所以还必须禁止对象的克隆,即在类内部私有化克隆方法
#在singleton类中增加私有化的__clone()方法
private function _clone(){}
五、总结
1、单例模式就是谩计的类最多只能得到一个对象
2、单例模式的设计规范就是“三私一公”
·私有化构造方法:禁止在类外无限实例化对象
·私有化克隆方法:禁止对象无限克隆对象
·私有化静态属性:保存类内部实例化得到的对象
·公有化静态方法:允许外部通过调用类内部方法获取对象
3、单例模式只是解决当前类对象的唯一性,如果还有其他功能诉求,可以在类中增加相应的其他类成员
4、单例模式的目的是为了保护资源的唯一性
唯一的资源能够让操作更加精确,如果两个一直在变化,消耗资源如果不同,就不能区分了。比如只有一块表,可以准确地告诉时间,如果有两块表,因为不能知道哪个时间是对的所以无法准确描述时间。