常用设计模式的总结

常用设计模式的总结

算法处理的是操作速度,而设计模式处理的是开发速度。在公司项目越来越多,集成度越来越高的情况下,运用设计模式写出高质量的代码很有必要。合理运用设计模式可以提高代码的可读性,复用性,可维护性,提高复杂业务的编写效率。

六大原则

1.单一职责原则:一个类只负责一项职责,提高类的可读性,降低类的复杂度,防止业务的变化让耦合的代码难以维护;
2.里氏替换原则:子类可以扩展父类的功能,但不能改变原有父类的功能。子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;
3.依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。这个原则很重要,很多框架都运用了这个原则,也是代码解耦的关键。
4.接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。避免接口的臃肿,也避免实现类实现一些本不需要实现的方法。实现类可以去实现多个接口来做到接口隔离;
5.迪米特原则:一个对象应该对其他对象保持最少的了解。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类影响也就越大。但过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合;
6.开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。用抽象构建框架,用实现扩展细节。

比较重要的设计模式

单例模式

确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例;
特点:三私一公
需要一个保存类的唯一实例的私有静态成员变量
构造函数必须声明为私有的,防止外部程序new一个对象从而失去单例的意义
克隆函数必须声明为私有的,防止对象被克隆
必须提供一个访问这个实例的公共静态方法(通常命名为getInstance,下面实例为getObject),从而返回唯一实例的一个引用。

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
<?php
/**
* Created by PhpStorm.
* User: skywing
* Date: 2018/7/4
* Time: 上午10:46
* Describe:单例模式
*/

class Singleton
{
private static $obj = null;//属性值为对象,默认为null

// 设置 一个封装的构造方法
private function __construct()
{
//不让NEW
}

private function __clone()
{
//不准克隆
}

//后门
public static function getObject()
{
echo "啊,我是后门,进吧!<br>";
if (self::$obj === null) {
echo "实例化一个对象<br>";
self::$obj = new self();//实例化一个对象
}
//返回的属性 其实就是本对象
return self::$obj;
}
}

/*Test::getObject();//使用静态方法访问该类里的方法
exit;*/

$t1 = Singleton::getObject();
$t2 = Singleton::getObject();
$t3 = Singleton::getObject();
$t4 = Singleton::getObject();
$t5 = Singleton::getObject();
$t6 = Singleton::getObject();
$t7 = Singleton::getObject();
$t8 = Singleton::getObject();

//判断 两个对象 是否是同一个对象
if ($t1 === $t6) {
echo "哦, Yes! 是同一个实例<br>";
} else {
echo "哦, No! 不是同一个实例<br>";
}

工厂模式

工厂模式是我们最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。使用工厂模式的好处是,如果你想要更改所实例化的类名等,则只需更改该工厂方法内容即可,不需逐一寻找代码中具体实例化的地方(new处)修改了。为系统结构提供灵活的动态扩展机制,减少了耦合。
根据抽象程度的不同,PHP工厂模式分为三种:
(1)简单工厂模式

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
<?php
header('Content-Type:text/html;charset=utf-8');
/**
*简单工厂模式(静态工厂方法模式)
*/

/**
* Interface people 人类
*/
interface people
{
public function say();
}

/**
* Class man 继承people的男人类
*/
class man implements people
{
// 具体实现people的say方法
public function say()
{
echo '我是男人<br>';
}
}

/**
* Class women 继承people的女人类
*/
class women implements people
{
// 具体实现people的say方法
public function say()
{
echo '我是女人<br>';
}
}

/**
* Class SimpleFactoty 工厂类
*/
class SimpleFactoty
{
// 简单工厂里的静态方法-用于创建男人对象
static function createMan()
{
return new man();
}

// 简单工厂里的静态方法-用于创建女人对象
static function createWomen()
{
return new women();
}

}

/**
* 具体调用
*/
$man = SimpleFactoty::createMan();
$man->say();
$woman = SimpleFactoty::createWomen();
$woman->say();

(2)工厂方法模式
定义一个用于创建对象的接口,让子类决定哪个类实例化。 他可以解决简单工厂模式中的封闭开放原则问题。

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<?php
header('Content-type:text/html;charset=utf-8');
/*
*工厂方法模式
*/

/**
* Interface people 人类
*/
interface people
{
public function say();
}

/**
* Class man 继承people的男人类
*/
class man implements people
{
// 实现people的say方法
function say()
{
echo '我是男人-hi<br>';
}
}

/**
* Class women 继承people的女人类
*/
class women implements people
{
// 实现people的say方法
function say()
{
echo '我是女人-hi<br>';
}
}

/**
* Interface createPeople 创建人物类
* 注意:与上面简单工厂模式对比。这里本质区别在于,此处是将对象的创建抽象成一个接口。
*/
interface createPeople
{
public function create();

}

/**
* Class FactoryMan 继承createPeople的工厂类-用于实例化男人类
*/
class FactoryMan implements createPeople
{
// 创建男人对象(实例化男人类)
public function create()
{
return new man();
}
}

/**
* Class FactoryMan 继承createPeople的工厂类-用于实例化女人类
*/
class FactoryWomen implements createPeople
{
// 创建女人对象(实例化女人类)
function create()
{
return new women();
}
}

/**
* Class Client 操作具体类
*/
class Client
{
// 具体生产对象并执行对象方法测试
public function test() {
$factory = new FactoryMan();
$man = $factory->create();
$man->say();

$factory = new FactoryWomen();
$man = $factory->create();
$man->say();
}
}

// 执行
$demo = new Client;
$demo->test();

(3)抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口。注意:这里和工厂方法的区别是:一系列(多个),而工厂方法只有一个。

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php
header('Content-type:text/html;charset=utf-8');
/*
* 抽象工厂模式
*/

/**
* Interface people 人类
*/
interface people
{
public function say();
}

/**
* Class OneMan 第一个男人类-继承people
*/
class OneMan implements people
{
// 实现people的say方法
public function say()
{
echo '男1:我喜欢你<br>';
}
}

/**
* Class TwoMan 第二个男人类-继承people
*/
class TwoMan implements people{
// 实现people的say方法
public function say()
{
echo '男2:我看上你了<br>';
}
}

/**
* Class OneWomen 第一个女人类-继承people
*/
class OneWomen implements people {
// 实现people的say方法
public function say()
{
echo '女1:我不喜欢你<br>';
}
}

/**
* Class TwoWomen 第二个女人类-继承people
*/
class TwoWomen implements people {
// 实现people的say方法
public function say()
{
echo '女2:滚一边玩去<br>';
}
}

/**
* Interface createPeople 创建对象类
* 注意:这里将对象的创建抽象成了一个接口。
*/
interface createPeople
{
// 创建第一个
public function createOne();
// 创建第二个
public function createTwo();

}

/**
* Class FactoryMan 用于创建男人对象的工厂类-继承createPeople
*/
class FactoryMan implements createPeople
{
// 创建第一个男人
public function createOne()
{
return new OneMan();
}

// 创建第二个男人
public function createTwo()
{
return new TwoMan();
}
}

/**
* Class FactoryWomen 用于创建女人对象的工厂类-继承createPeople
*/
class FactoryWomen implements createPeople
{
// 创建第一个女人
public function createOne()
{
return new OneWomen();
}

// 创建第二个女人
public function createTwo()
{
return new TwoWomen();
}
}

/**
* Class Client 执行测试类
*/
class Client {

// 具体生成对象和执行方法
public function test() {
// 男人
$factory = new FactoryMan();
$man = $factory->createOne();
$man->say();

$man = $factory->createTwo();
$man->say();

// 女人
$factory = new FactoryWomen();
$man = $factory->createOne();
$man->say();

$man = $factory->createTwo();
$man->say();

}
}

// 执行
$demo = new Client;
$demo->test();

原型设计模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
(1)浅拷贝模式
直接copy,拷贝了源对象的引用地址等,所以原来内容变化,新内容变化。

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
78
79
80
81
82
83
84
85
86
87
88
<?php
header('Content-type:text/html;charset=utf-8');

/**
* PHP原型模式-潜拷贝
*/

/**
* Interface Prototype 抽象原型模式
*/
interface Prototype
{
// 定义拷贝自身方法啊
public function copy();
}

/**
* Class ConcretePrototype 具体原型模式
*/
class ConcretePrototype implements Prototype
{

private $name;

public function __construct($name)
{
$this->name = $name;
}

public function setName($name)
{
$this->name=$name;
}

public function getName()
{
return $this->name;
}

/**
* 拷贝自身
*
* @return ConcretePrototype 返回自身
*/
public function copy()
{
return clone $this;//浅拷贝
}
}

/**
* 测试潜拷贝
*/

class LatentCopyDemo{
public $array;
}

/**
* Class Client 客户端
*/
class Client{

/**
* 测试方法
*/
public static function test(){

$demo = new LatentCopyDemo();
$demo->array = array(1,2);

$object1 = new ConcretePrototype($demo);
$object2 = $object1->copy();

var_dump($object1->getName());
echo '<br/>';
var_dump($object2->getName());
echo '<br/>';

$demo->array = array(3, 4);
var_dump($object1->getName());
echo '<br />';
var_dump($object2->getName());
echo '<br />';
}
}

Client::test();

(2)深拷贝模式
深copy通过序列化和反序列化完成copy,新copy的内容完全复制原来的内容。原来的内容变化,新内容不变。

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
78
79
80
81
82
83
84
85
86
87
88
89
90
<?php
header('Content-type:text/html;charset=utf-8');

/**
* PHP原型模式-深拷贝
*/

/**
* Interface Prototype 抽象原型模式
*/
interface Prototype
{
// 定义拷贝自身方法啊
public function copy();
}

/**
* Class ConcretePrototype 具体原型模式
*/
class ConcretePrototype implements Prototype
{

private $name;

public function __construct($name)
{
$this->name = $name;
}

public function setName($name)
{
$this->name = $name;
}

public function getName()
{
return $this->name;
}

/**
* 拷贝自身
*
* @return ConcretePrototype 返回自身
*/
public function copy()
{
$serialize_obj = serialize($this);
$clone_obj = unserialize($serialize_obj);
return $clone_obj;
}
}

/**
* 测试拷贝
*/

class DeepCopyDemo{
public $array;
}

/**
* Class Client 客户端
*/
class Client{

/**
* 测试方法
*/
public static function test(){

$demo = new DeepCopyDemo();
$demo->array = array(1,2);

$object1 = new ConcretePrototype($demo);
$object2 = $object1->copy();

var_dump($object1->getName());
echo '<br/>';
var_dump($object2->getName());
echo '<br/>';

$demo->array = array(3, 4);
var_dump($object1->getName());//值会变成3,4
echo '<br />';
var_dump($object2->getName());
echo '<br />';
}
}

Client::test();