跳转至

设计模式

并非所有开发语言都支持所有设计模式,有的开发语言只支持个别设计模式。

创建型模式(Creational)

关注对象的实例化过程,包括了如何实例化对象、隐藏对象的创建细节等。

单例模式(Singleton Pattern)

确保一个类只有一个实例,并提供该实例的全局访问点。

数据库类设计,只连接一次数据库,防止打开多个数据库连接

使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。

私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Single {
    private $name;//声明一个私有的实例变量
    private function __construct(){//声明私有构造方法为了防止外部代码使用new来创建对象。

    }

    static public $instance;//声明一个静态变量(保存在类中唯一的一个实例)
    static public function getinstance(){//声明一个getinstance()静态方法,用于检测是否有实例对象
        if(!self::$instance) self::$instance = new self();
        return self::$instance;
    }

    public function setname($n){ $this->name = $n; }
    public function getname(){ return $this->name; }
}

$oa = Single::getinstance();
$ob = Single::getinstance();
$oa->setname('hello php world');
$ob->setname('good morning php');
echo $oa->getname();//good morning php
echo $ob->getname();//good morning php

简单工厂

在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。

简单工厂又叫静态工厂方法模式,简单工厂模式是通过一个静态方法创建对象的。

违反开闭原则(对于扩展是开放的,对于修改是关闭的)

新增时需要改动原有类文件,在里面新增方法或判断。

调用时用同一个对象,但用的方法不一样,或传进去的参数不一样。如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
SimpleFactoty::creatA();
SimpleFactoty::creatB();
SimpleFactoty::creatC();

// or

SimpleFactoty::creat("A");
SimpleFactoty::creat("B");
SimpleFactoty::creat("C");
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
interface  people
{
    function marry();
}

class man implements people
{
    function marry()
    {
        echo '送玫瑰,送戒指!';
    }
}

class women implements people
{
    function marry()
    {
        echo '穿婚纱!';
    }
}

class SimpleFactoty
{
    // 简单工厂里的静态方法
    static function createMan()
    {
        return new     man;
    }

    static function createWomen()
    {
        return new     women;
    }

}

SimpleFactoty::createMan()->marry();
// 送玫瑰,送戒指!
SimpleFactoty::createWomen()->marry();
// 穿婚纱!

简单工厂: 调用时SimpleFactoty一样,createMan方法不一样 工厂方法: 调用时SimpleFactoty不一样,createMan方法一样

工厂方法

定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。

遵循开闭原则。

新增方法不用改原有类文件,新增文件后继承上游类或接口即可调用。

调用时,对象不一样,但调用方法和返回类型皆为一致。

如:

1
2
3
4
5
<?php
FactoryA::create();
FactoryB::create();
FactoryC::create();
?>

使用场景:

  • 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
  • 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
  • 设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。

在工厂方法中,由子类来创建对象。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
interface  people
{
    function marry();
}

class man implements people
{
    function marry()
    {
        echo '送玫瑰,送戒指!';
    }
}

class women implements people
{
    function marry()
    {
        echo '穿婚纱!';
    }
}

interface  createMan
{  // 注意了,这里是简单工厂本质区别所在,将对象的创建抽象成一个接口。
    function create();
}

class FactoryMan implements createMan
{
    function create()
    {
        return new man;
    }
}

class FactoryWomen implements createMan
{
    function create()
    {
        return new women;
    }
}

FactoryMan::create()->marry();
//送玫瑰,送戒指!
FactoryWomen::create()->marry();
//穿婚纱!
?>

与简单工厂不同的是前面的FactoryMan对象是变化的,create方法是固定的。

抽象工厂

提供一个接口,用于创建 相关的对象家族 。

抽象工厂模式是工厂模式的一个扩展,如果抽象工厂只有一个产品体系就会退化成工厂模式。属于简单工厂和工厂模式的合体。

违反开闭原则

新增时 可能 需要改动原有类文件,在里面新增方法或判断。同样要继承上游类或接口。

调用时,对象和调用方法都可不一样。

如:

1
2
3
4
5
6
<?php
FactoryA::create();
FactoryB::change();
FactoryC::change();
FactoryD::delete();
?>

体现出了面向接口编程的思想,其实就是用工厂方法生产具有多维度变化的产品类。

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 工厂里加代码,又要在具体的实现加代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?php
interface  people
{
    function marry();
}

class Oman implements people
{
    function marry()
    {
        echo '美女,我送你玫瑰和戒指!';
    }
}

class Iman implements people
{
    function marry()
    {
        echo '我偷偷喜欢你';
    }
}

class Owomen implements people
{
    function marry()
    {
        echo '我要穿婚纱!';
    }
}

class Iwomen implements people
{
    function marry()
    {
        echo '我好害羞哦!!';
    }
}

interface  createMan
{  // 注意了,这里是本质区别所在,将对象的创建抽象成一个接口。
    function createOpen(); //分为 内敛的和外向的

    function createIntro(); //内向
}

class FactoryMan implements createMan
{
    function createOpen()
    {
        return new  Oman;
    }

    function createIntro()
    {
        return new Iman;
    }
}

class FactoryWomen implements createMan
{
    function createOpen()
    {
        return new  Owomen;
    }

    function createIntro()
    {
        return new Iwomen;
    }
}

FactoryMan::createOpen()->marry();  //美女,我送你玫瑰和戒指!
FactoryMan::createIntro()->marry(); //我偷偷喜欢你

FactoryWomen::createOpen()->marry();    //我要穿婚纱!
FactoryWomen::createIntro()->marry();   //我好害羞哦!!
?>

生成器

封装一个对象的构造过程,并允许按步骤构造。

原型模式

使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。

行为型

责任链

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

命令

将命令封装成对象中,具有以下作用:

  • 使用命令来参数化其它对象
  • 将命令放入队列中进行排队
  • 将命令的操作记录到日志中
  • 支持可撤销的操作

解释器

为语言创建解释器,通常由语言的语法和语法分析来定义。

迭代器

提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。

中介者

集中相关对象之间复杂的沟通和控制方式。

备忘录

在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。

观察者

定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。

主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

状态

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。

策略

定义一系列算法,封装每个算法,并使它们可以互换。

策略模式可以让算法独立于使用它的客户端。

模板方法

定义算法框架,并将一些步骤的实现延迟到子类。

通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

访问者

为一个对象结构(比如组合结构)增加新能力。

空对象

使用什么都不做

的空对象来代替 NULL。

一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。

结构型

适配器

把一个类接口转换成另一个用户需要的接口。

桥接

将抽象与实现分离开来,使它们可以独立变化。

组合

将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。

装饰

为对象动态添加功能。

外观

提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。

享元

利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。

代理

控制对其它对象的访问。