原型模式

scorlw 发布于

原型模式

设计模式

Prototype模式是一对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用 Prototype模式创建的实例,具有与原型一样的数据。

1) 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。

2) 目标对象是原型对象的一个克隆。也就是说,通过 Prototype模式创建的对象,不仅仅与
原型对象具有相同的結构,还与原型对象具有相同的值。

3) 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。

image-20201007230858097

Prototype模式提供了一个通过已存在对象进行新对象创建的接口(Clone), Clone()实现和具体的实现语言相关,在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
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
#include <iostream>
#include <string>
#include <string.h>

using namespace std;

class Person
{
public:
virtual Person* clone() = 0;
virtual void printT() = 0;

protected:
private:
};

class CppProgrammer:public Person
{
public:
CppProgrammer()
{
m_name = "";
m_age = 0;
m_ptr = "aaaa";
};
CppProgrammer(string name, int age)
{
m_name = name;
m_age = age;
m_ptr = "aaaa";
};
void setPtr(char* p)
{
if(m_ptr != NULL)
{
delete m_ptr;
}
m_ptr = new char[strlen(p) + 1];
strcpy(m_ptr, p);
}
virtual void printT()
{
cout << "name:" << m_name << endl;
cout << "age:" << m_age << endl;
if(m_ptr != NULL){
printf(m_ptr);
printf("\n");
//cout << "ptr:" << *m_ptr << endl;
}
};
virtual Person* clone()
{
CppProgrammer* tmp = new CppProgrammer();
//tmp->m_name = m_name, tmp->m_age = m_age;//与下一句一样
*tmp = *this;
return tmp;
};
//如果成员中包括指针的话,不能直接使用clone中的浅拷贝,需要重定义=来实现指针的深拷贝
CppProgrammer operator=(CppProgrammer& tmp)
{
cout << "my=" << endl;
m_name = tmp.m_name;
m_age = tmp.m_age;
if(tmp.m_ptr == NULL)
{
m_ptr = NULL;
}
else
{
m_ptr = new char(strlen(tmp.m_ptr) + 1);
strcpy(m_ptr, tmp.m_ptr);
}
return *this;
};
protected:
private:
string m_name;
int m_age;
char* m_ptr;
};

int main()
{
Person* c1 = new CppProgrammer("Tom", 12);
c1->printT();

Person* c2 = c1->clone();
c2->printT();

delete c1;
c2->printT();
cout << "Hello world!" << endl;
return 0;
}

输出:

1
2
3
4
5
6
7
8
9
10
11
name:Tom
age:12
aaaa
my=
name:Tom
age:12
aaaa
name:Tom
age:12
aaaa
Hello world!

注意

需要注意clone函数中只是进行了类的浅拷贝,如果类的成员有指针的话,此时拷贝过去的也只是指针所指向的地址的值。所以需要重新定义赋值函数(或者定义复制构造函数)。

指针的深拷贝代码如下:

1
2
3
4
5
6
7
8
9
if(tmp.m_ptr == NULL)
{
m_ptr = NULL;
}
else
{
m_ptr = new char(strlen(tmp.m_ptr) + 1);
strcpy(m_ptr, tmp.m_ptr);
}