设计模式
并非所有开发语言都支持所有设计模式,有的开发语言只支持个别设计模式。
创建型模式(Creational)
关注对象的实例化过程,包括了如何实例化对象、隐藏对象的创建细节等。
单例模式(Singleton Pattern)
确保一个类只有一个实例,并提供该实例的全局访问点。
数据库类设计,只连接一次数据库,防止打开多个数据库连接
使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。
私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。
1class Single {
2 private $name;//声明一个私有的实例变量
3 private function __construct(){//声明私有构造方法为了防止外部代码使用new来创建对象。
4
5 }
6
7 static public $instance;//声明一个静态变量(保存在类中唯一的一个实例)
8 static public function getinstance(){//声明一个getinstance()静态方法,用于检测是否有实例对象
9 if(!self::$instance) self::$instance = new self();
10 return self::$instance;
11 }
12
13 public function setname($n){ $this->name = $n; }
14 public function getname(){ return $this->name; }
15}
16
17$oa = Single::getinstance();
18$ob = Single::getinstance();
19$oa->setname('hello php world');
20$ob->setname('good morning php');
21echo $oa->getname();//good morning php
22echo $ob->getname();//good morning php
简单工厂
在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。
简单工厂又叫静态工厂方法模式,简单工厂模式是通过一个静态方法创建对象的。
违反开闭原则(对于扩展是开放的,对于修改是关闭的)
新增时需要改动原有类文件,在里面新增方法或判断。
调用时用同一个对象,但用的方法不一样,或传进去的参数不一样。如:
1<?php
2SimpleFactoty::creatA();
3SimpleFactoty::creatB();
4SimpleFactoty::creatC();
5
6// or
7
8SimpleFactoty::creat("A");
9SimpleFactoty::creat("B");
10SimpleFactoty::creat("C");
1<?php
2interface people
3{
4 function marry();
5}
6
7class man implements people
8{
9 function marry()
10 {
11 echo '送玫瑰,送戒指!';
12 }
13}
14
15class women implements people
16{
17 function marry()
18 {
19 echo '穿婚纱!';
20 }
21}
22
23class SimpleFactoty
24{
25 // 简单工厂里的静态方法
26 static function createMan()
27 {
28 return new man;
29 }
30
31 static function createWomen()
32 {
33 return new women;
34 }
35
36}
37
38SimpleFactoty::createMan()->marry();
39// 送玫瑰,送戒指!
40SimpleFactoty::createWomen()->marry();
41// 穿婚纱!
简单工厂: 调用时
SimpleFactoty
一样,createMan
方法不一样 工厂方法: 调用时SimpleFactoty
不一样,createMan
方法一样
工厂方法
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
遵循开闭原则。
新增方法不用改原有类文件,新增文件后继承上游类或接口即可调用。
调用时,对象不一样,但调用方法和返回类型皆为一致。
如:
1<?php
2FactoryA::create();
3FactoryB::create();
4FactoryC::create();
5?>
使用场景:
- 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
- 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
- 设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。
在工厂方法中,由子类来创建对象。
1<?php
2interface people
3{
4 function marry();
5}
6
7class man implements people
8{
9 function marry()
10 {
11 echo '送玫瑰,送戒指!';
12 }
13}
14
15class women implements people
16{
17 function marry()
18 {
19 echo '穿婚纱!';
20 }
21}
22
23interface createMan
24{ // 注意了,这里是简单工厂本质区别所在,将对象的创建抽象成一个接口。
25 function create();
26}
27
28class FactoryMan implements createMan
29{
30 function create()
31 {
32 return new man;
33 }
34}
35
36class FactoryWomen implements createMan
37{
38 function create()
39 {
40 return new women;
41 }
42}
43
44FactoryMan::create()->marry();
45//送玫瑰,送戒指!
46FactoryWomen::create()->marry();
47//穿婚纱!
48?>
与简单工厂不同的是前面的
FactoryMan
对象是变化的,create
方法是固定的。
抽象工厂
提供一个接口,用于创建 相关的对象家族 。
抽象工厂模式是工厂模式的一个扩展,如果抽象工厂只有一个产品体系就会退化成工厂模式。属于简单工厂和工厂模式的合体。
违反开闭原则
新增时 可能 需要改动原有类文件,在里面新增方法或判断。同样要继承上游类或接口。
调用时,对象和调用方法都可不一样。
如:
1<?php
2FactoryA::create();
3FactoryB::change();
4FactoryC::change();
5FactoryD::delete();
6?>
体现出了面向接口编程的思想,其实就是用工厂方法生产具有多维度变化的产品类。
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 工厂里加代码,又要在具体的实现加代码
1<?php
2interface people
3{
4 function marry();
5}
6
7class Oman implements people
8{
9 function marry()
10 {
11 echo '美女,我送你玫瑰和戒指!';
12 }
13}
14
15class Iman implements people
16{
17 function marry()
18 {
19 echo '我偷偷喜欢你';
20 }
21}
22
23class Owomen implements people
24{
25 function marry()
26 {
27 echo '我要穿婚纱!';
28 }
29}
30
31class Iwomen implements people
32{
33 function marry()
34 {
35 echo '我好害羞哦!!';
36 }
37}
38
39interface createMan
40{ // 注意了,这里是本质区别所在,将对象的创建抽象成一个接口。
41 function createOpen(); //分为 内敛的和外向的
42
43 function createIntro(); //内向
44}
45
46class FactoryMan implements createMan
47{
48 function createOpen()
49 {
50 return new Oman;
51 }
52
53 function createIntro()
54 {
55 return new Iman;
56 }
57}
58
59class FactoryWomen implements createMan
60{
61 function createOpen()
62 {
63 return new Owomen;
64 }
65
66 function createIntro()
67 {
68 return new Iwomen;
69 }
70}
71
72FactoryMan::createOpen()->marry(); //美女,我送你玫瑰和戒指!
73FactoryMan::createIntro()->marry(); //我偷偷喜欢你
74
75FactoryWomen::createOpen()->marry(); //我要穿婚纱!
76FactoryWomen::createIntro()->marry(); //我好害羞哦!!
77?>
生成器
封装一个对象的构造过程,并允许按步骤构造。
原型模式
使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。
行为型
责任链
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
命令
将命令封装成对象中,具有以下作用:
- 使用命令来参数化其它对象
- 将命令放入队列中进行排队
- 将命令的操作记录到日志中
- 支持可撤销的操作
解释器
为语言创建解释器,通常由语言的语法和语法分析来定义。
迭代器
提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
中介者
集中相关对象之间复杂的沟通和控制方式。
备忘录
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
观察者
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。
状态
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
策略
定义一系列算法,封装每个算法,并使它们可以互换。
策略模式可以让算法独立于使用它的客户端。
模板方法
定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
访问者
为一个对象结构(比如组合结构)增加新能力。
空对象
使用什么都不做
的空对象来代替 NULL。
一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。
结构型
适配器
把一个类接口转换成另一个用户需要的接口。
桥接
将抽象与实现分离开来,使它们可以独立变化。
组合
将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。
装饰
为对象动态添加功能。
外观
提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。
享元
利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。
代理
控制对其它对象的访问。