PHP设计模式之原型模式

工厂方法模式会给添加产品家族时产生一定的耦合,就是每次添加一个产品,都被迫创建一个相关的具体创建者(即子类工厂)。在一个快速增长的系统里会包含越来越多的产品 ,而维护这种关系便会很快厌烦。
一个避免这种依赖的办法就是使用 PHP 的 clone 关键字复制已存在的具体产品。然后 ,具体产品类本身便成为他们自己生成的基础,这就是原型模式。
原型模式的理解
一个人好比一个对象,当创建这个人的时候,还是比较初级的人,什么都不懂,但经过一定的进化,这个人有了各种技能和知识。那么通过克隆可以完全复制出一个包含了各种技能和知识的人,这就是原型模式。如果采用创建对象,那么创建出来人还是比较初级,还必须经过一定的进化,所以会非常消耗资源。
一张表,通过创建对象获得,还需要通过同样的一样表进行比对,那么就必须在创建一次,这是比较消耗资源的。如果第一次创建对象获得了表,第二次通过克隆复制同样的表进行比对,那么是不是很节约呢?

实例一

普通方式创建对象

demo1.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
header('Content-Type:text/html; charset=utf-8');

class Person{
public function __construct(){
// 这里初始化,把人进化成有知识有技能的人
}
}

$arr = [1, 2, 3, 4, 5];
$obj = [];

foreach($arr as $value){
$obj[] = new Person();
}

var_dump($obj);

原型模式创建对象

demo2.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
header('Content-Type:text/html; charset=utf-8');

class Person{
public function __construct(){
// 这里初始化,把人进化成有知识有技能的人
}
}

$arr = [1, 2, 3, 4, 5];
$obj = [];
$person = new Person();

foreach($arr as $value){
$obj[] = clone $person;
}

var_dump($obj);

实例二

普通方式创建对象

demo3.php

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
<?php
header('Content-Type:text/html; charset=utf-8');

abstract class File{
abstract public function size();
}

class EXE extends File{
public function size(){
return 'EXE大小为2M';
}
}

class PHP extends File{
public function size(){
return 'PHP大小为5M';
}
}

abstract class Image{
abstract public function getWidth();
abstract public function getHeight();
}

class PNG extends Image{
public function getWidth(){
return 'PNG长度为100';
}
public function getHeight(){
return 'PNG高度为200';
}
}

class GIF extends Image{
private $exe;

public function __construct(){
$this->exe = new EXE();
}

public function getWidth(){
return 'GIF长度为100';
}
public function getHeight(){
return 'GIF高度为200';
}
}

class Factory{
private $image;
private $file;

public function __construct(Image $image, File $file){
$this->image = $image;
$this->file = $file;
}

public function getImage(){
return $this->image;
}

public function getFile(){
return $this->file;
}
}

$factory = new Factory(new GIF(), new PHP());
$gif = $factory->getImage();
echo $gif->getWidth();

原型模式创建对象

简单工厂的原型模式

demo4.php

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
<?php
header('Content-Type:text/html; charset=utf-8');

abstract class File{
abstract public function size();
}

class EXE extends File{
public function size(){
return 'EXE大小为2M';
}
}

class PHP extends File{
public function size(){
return 'PHP大小为5M';
}
}

abstract class Image{
abstract public function getWidth();
abstract public function getHeight();
}

class PNG extends Image{
public function getWidth(){
return 'PNG长度为100';
}
public function getHeight(){
return 'PNG高度为200';
}
}

class GIF extends Image{
private $exe;

public function __construct(){
$this->exe = new EXE();
}

public function __clone(){
$this->exe = clone $this->exe; // 深复制
}

public function getWidth(){
return 'GIF长度为100';
}
public function getHeight(){
return 'GIF高度为200';
}
}

class Factory{
private $image;
private $file;

public function __construct(Image $image, File $file){
$this->image = $image;
$this->file = $file;
}

public function getImage(){
return clone $this->image;
}

public function getFile(){
return clone $this->file;
}
}

$factory = new Factory(new GIF(), new PHP());
$gif = $factory->getImage();
echo $gif->getWidth();

原型模式的对象克隆和创建对象的比较
原型模式提供了减少复杂对象所需开销的方式。单例模式是保持一个实例,而原型模式
是为了更加节约的生成多个实例。因为使用 new 创建对象极耗资源,而克隆则性能高出很
多。

浅复制与深复制
如果产品对象又引用了其他对象,那么会得到其他对象的引用,这个时候,我们也想得到其他对象的克隆,所以必须采用深复制(__clone())来进行处理。而 clone()方法则为浅复制。