设计模式
学习目标:了解设计模式的概念,掌握设计模式在开发中的实际应用
- 单例模式
- 工厂模式
概念
设计模式:Design pattern, 是软件开发人员在软件开发过程中面临的一般问题的解决方案
- 解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的
- 设计模式有很多(23种之多),在PHP中通常只用两种设计模式
- 单例模式
- 工厂模式
示例
1、设计模式是针对某种常见的需求而提供的一类解决方案
- windows系统的资源管理器用来显示计算机资源占用的情况
- 资源管理器本身要占用资源
- 如果要打开多个资源管理器,显示的资源占用情况应该一致,而资源管理器占用了更多的资源
- 因此:资源管理器一个就够了
- 针对上述需求:我们可以设计一种解决方案,保证资源管理器只产生一个
- 后来发现其他的需求也有同样的问题:数据库连接资源一个用户一个连接就够了,所以上述方案可以作为一种类似问题的通用解决方案,此时就可以理解为一个设计模式
小结
1、设计模式是一类问题的通用解决方案
2、设计模式的存在,可以帮助我们快速的解决某类特定需求问题
3、通常设计模式的出现,都会需要额外增加开发难度和开发时间,因此我们要根据项目的需求来选择
1、单例模式
目标:理解单例模式的概念,掌握单例模式解决方案
概念
单例模式:singleton,是一种类的设计只会最多产生一个对象的设计思想
- 单例模式的类只能在一次运行中产生一个对象
- 单例模式为了解决如何只产生一个对象,需要使用以下解决方案,简称
三私一公
:
- 私有化构造方法:不让在外部产生多个对象
- 私有化克隆方法:不允许对象被克隆产生新对象
- 公有化静态方法:运行进入类内部产生对象
- 私有化静态属性:保存已经产生的对象
步骤
1、定义空类
2、杜绝能够产生多个对象的方式:构造方法私有化
3、想办法产生对象:进入类内部产生对象
4、想办法控制内部对象生产:只生产一个
5、杜绝外部拿着已有对象产生新对象:克隆方法私有化
示例
1、首先定义一个空类,叫做Singleton
# 创建一个空类
class Singleton{
}
2、对象的产生是通过实例化产生的,而实例化是一种不可控行为,即可以产生无限多个对象,所以应该禁止:即”禁止实例化“,之所以是引号,是因为只能禁止在类外部实例化对象,私有化构造方法
# 在上述类中增加私有化构造方法
class Singleton{
private function __construct(){}
}
# 尝试外部实例化
$s = new Singleton(); # 致命错误:不能访问私有方法
3、一旦外部不能实例化对象了,那就意味着根本“不可能”产生对象了,此时就只能想办法在还没有产生对象的时候就进入到“类内部”,意味着只能通过静态方法
让类直接进入到类的内部
# 在上述类中增加公有静态方法
public static function getInstance(){
}
4、进入类的内部依然还是没有对象,此时需要在静态方法内部进行对象实例化,并且把得到的对象返回到外部
# 修改公有静态方法:获取对象,并返回给外部调用出
public static function getInstance(){
return new self();
}
# 外部获取对象
$s = Singleton::getInstance();
5、此方法开启了实例化对象的窗口,但是此时新问题出现:无限调用静态方法依然可以得到多个对象。如果想要该方法只返回一个对象,就得保证类内部有办法存着某个产生的对象,第一次产生新的,后面返回旧的。此时需要使用静态属性
# 增加静态属性:私有,不允许外部修改,否则外部修改之后就没有意义了
private static $object = NULL; # 初始化为NULL,没有对象
# 修改静态方法
public static function getInstance(){
# 判断内部属性是否存在对象(is_object函数):最好的判定是存的对象是当前类的 instanceof
if(!(self::$object instanceof self)){
# 当前保存的内容不是当前类的对象
self::$object = new self();
}
# 返回对象给外部
return self::$object;
}
6、此时可以保证外部无论多少次调用公有静态方法获取实例,都会只得到一个对象。但是此时外部对象依然可以产生新的对象:因为克隆,所以还必须禁止对象的克隆,即在类内部私有化克隆方法
# 在Singleton类中增加私有化的__clone()方法
private function __clone(){}
总结
1、单例模式就是设计的类最多只能得到一个对象
2、单例模式的设计规范就是“三私一公”
- 私有化构造方法:禁止在类外无限实例化对象
- 私有化克隆方法:禁止对象无限克隆对象
- 私有化静态属性:保存类内部实例化得到的对象
- 公有化静态方法:允许外部通过调用类内部方法获取对象
3、单例模式只是解决当前类对象的唯一性,如果还有其他功能诉求,可以在类中增加相应的其他类成员
4、单例模式的目的是为了保护资源的唯一性
2、工厂模式
目标:理解工厂模式的概念,掌握工厂模式解决方案
概念
工厂模式:factory,是指像工厂一样流水线生产对象,由一个地方生产对象,其他位置就不需要额外实例化对象,从而可以方便后期代码统一的维护
- 工厂模式是用来代生产对象
- 工厂模式下可以方便隐藏真实的类结构,因此也更加安全
- 工厂模式不需要关注工厂是如何产生对象,只需要让工厂产生对象
步骤
1、创建不同类
2、创建生产对象的工厂类
3、调用工厂类产生对象
示例
1、工厂模式针对的是“相同模型”的统一产出,即使用工厂模式产出对象对应的类都有相同的结构或者功能。所以,首先要有一批具有类似功能的类(其实本质是同样的大类下的小类)
# 三个类文件
# 人是一种大类,人下应该有男人、女人、人妖,各自成类
class Man{
public function display(){
echo '这是男人<br/>';
}
}
class Woman{
public function display(){
echo '这是女人<br/>';
}
}
class Ladyboy{
public function display(){
echo '这是人妖<br/>';
}
}
2、使用工厂模式,就需要增加一个工厂类:HumanFactory
# 人类工厂
class HumanFactory{
public function getInstance($classname){
return new $classname(); # 可变变量使用
}
}
$hf = new HumanFactory();
$m = $hf->getInstance('Man');
$m->display(); # 这是男人
$w = $hf->getInstance('Woman');
$w->display(); # 这是女人
3、上述工厂类在对象生产的时候,额外产生了一个工厂类的对象,该对象无实际含义,因此可以使用更优的方式来生产对象:静态工厂
# 静态人类工厂
class HumanFactory{
public static function getInstance($classname){
return new $classname(); # 可变变量使用
}
}
$m = HumanFactory::getInstance('Man');
$m->display(); # 这是男人
$w = HumanFactory::getInstance('Woman');
$w->display(); # 这是女人
4、以上模式虽然也是工厂生产对象,但是是建立在使用者知道类名的前提下,而且如果原类名修改,依然需要多处修改代码,所以没有达到工厂模式的真实目的。修改工厂模式
# 静态人类工厂
class HumanFactory{
public static function getInstance($flag){ # flag只是一种标志:不是类名
# $flag可以是m代表Man,w代表Woman,L代表Ladyboy
switch($flag){
case 'm':
return new Man();
case 'w':
return new Woman();
case 'L':
return new Ladyboy();
default:
return null; # 匹配失败,返回空
}
}
}
$m = HumanFactory::getInstance('m');
$m->display(); # 这是男人
$w = HumanFactory::getInstance('w');
$w->display(); # 这是女人
小结
1、工厂模式是一种按需生产对象的模式(一个工厂生产的对象应该相似)
2、工厂模式通常是需要在大型项目中,会出现很多的相同功能的类,此时可以使用工厂产生对象
3、工厂模式的优点是能够方便后期对类的维护(更名)
4、工厂模式的缺点是随着功能增加,会需要增加很多开发量(开发多个工厂):以上只是一种简单工厂模式,复杂的工厂模式会有不同的工厂,调用时需要使用不同工厂来实现对象生产