设计模式学习(四) 原型模式 Prototype

1. 原型模型的概念与类图

原型模式,其具体的应用情况是将一个复杂的对象设计为具有自我复制功能,其统一一套接口。其实现过程和拷贝构造函数很像,即对一个类进行深拷贝/浅拷贝得到其大量的复制体,不过有所区别的原型模型的原型为抽象基类,而拷贝构造函数所有的类中几乎都有。其具体的类图构造如下:
原型模式类图
其类图构造十分简单,在主函数main中调用抽象基类来与其子类不断的new出其克隆对象,从而实现对一个复杂的抽象基类的多方面使用。其子类的通过抽象基类的接口在创建类,同时由于主函数中均为使用抽象基类作为构造对象,那么子类中的所有自有函数都无法使用,只能使用抽象基类统一的接口。

2. 原型模式的代码实现与个人理解

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
	virtual Person* Clone() = 0;
	virtual void Printself() = 0;
};

class cppPerson : public Person
{
public:
	cppPerson()
	{
		m_name = "Temp";
		m_age = 18;
	}
	cppPerson(string name,int age)
	{
		m_name = name;
		m_age = age;
	}
	Person* Clone()
	{
		cppPerson* temp = new cppPerson;
		*temp = *this;
		//这行代码等价于下,为深拷贝
		//temp->m_age = this->m_age;
		//temp->m_name = this->m_name;
		//这行代码则为浅拷贝,指针直接替换
		//temp = this;
		return temp;
	}
	void Printself()
	{
		cout << "m_name:" << m_name << "  m_age:" << m_age << endl;
	}

	void setName(string name)
	{
		m_name = name;
	}
	void setAge(int age)
	{
		m_age = age;
	}
private:
	string m_name;
	int m_age;
};

int main()
{
	Person* people = new cppPerson("mike", 21);
	people->Printself();
	Person* second_people = people->Clone();
	second_people->Printself();

	cppPerson* third_people = new cppPerson("jack", 22);
	third_people->Printself();
	Person* fouth_people = third_people->Clone();
	fouth_people->Printself();

	third_people->setAge(30);    //这里更改了third_people的值,来验证上面的Clone是深拷贝还是浅拷贝
	third_people->Printself();
	fouth_people->Printself();
}

在代码实现中,Clone函数的构造即为原型函数的核心,其决定了子类的克隆对象,究竟是深拷贝还是浅拷贝。

这里值得一提的就是本代码中Clone函数中的*temp = *this语句,这里是一个标准的指针对象拷贝赋值,可直接等价于temp->m_age = this->m_age和temp->m_name = this->m_name这两个语句,因为这里是调用this指针指向的本类数据,对temp指针指向的temp类数据进行了更改,得到的temp指针指向的数据更新,而其内存仍为另一块区域,这是一种深拷贝;而如果使用temp = this时,则是对指针本身被赋值,而指针本身作为一个变量,其内部数据为所指向的地址,此操作过后temp指针指向的地址也就变成了this指针指向的地址,成为了一个浅拷贝。

然后在最后,也想谈一下我个人对于数组与指针的看法,今年1月份去华为面试实习生时被问到了这个问题,我觉得我当时答的着实很烂,现在正好又碰到了类似的问题,想再提一下:

首先,数组和指针不是一个东西,数组就是数组,指针就是指针,两者切不可混为一谈。

然后,数组在定义时需要为其确定空间大小,比如int a[10]这样的语句,在定义完成后,编译器会给这个数组专门开辟一块内存给予其使用,在对数组的内容赋值时,如a[1] = 1,也就是对这快内存中,所赋值内容对应的内存空间进行赋值。调用数组时,如a[1]+1之类,这里的a[1]相当于两步,一是读取a[1]的对应内存地址,二是读取对应的内存地址内的值。

而指针,其作为一种变量,其内部存储的数据为所指向的数据的地址,在调用指针时,不使用解引用符就是调用其内部的数据(即存储的地址信息),使用解引用符号时,则是调用其指向的地址中,存储的数据。从调用的过程来看,使用解引用符号*p调用指针,和使用a[1]调用数组内部数据,实现是一样的,都是读取地址信息,然后读取地址内存贮的数据。

但是这也是指针和数组的区别所在了,指针自身只是一个存储地址信息的变量,其自身占最小的内存4个字节(根据CPU的寻址空间而定)。而数组在定义时,是系统为其大小而分配了一块内存,这块内存的每个小块都被数组所命名了,也就是说数组就是给分配他的内存都起了别名,调用这些别名时就是调用了这些内存。这些别名指向的这些内存是无法更改的,分配给了他就一直固守到最后,而不能像指针一样灵活变化。

通俗点来说,指针就像是是一个引路人,但是只对应一个地方,他自己也是人,也需要空间提供给他,但是他所对应的地方可以自由变换,也可以通过指针找到他所对应的地方,在这块地方上盖房子修高楼,虽然这块地方变了,但是指针还是对应的这个地方。而数组就是一出生就定死在了一个地方,不过他是一堆兄弟一起被定死在了一个地方,每个人数组内的人都只能对应自己出生时的那块地方。

总结来说,指针与数组其内部存储的其实都是指向的内存地址,不过数组由于被包装了一层,在调用时直接执行了解引用操作,而指针还需要解引用才能调用对应的数据。所以说,数组就像出生就有了房子的人,一辈子被拘束在那个地方,即使房子里空无一物,他也有自己的家。而指针永远都是只是一个指向别人房子的人,他自己所拥有的空间是所有内存中最小的是,一旦他失去了所指向的地方,那么他就成了一个野指针,一辈子只能孤独飘荡,没有他所能依靠的家。倘若有人找上了野指针来指路,那么只会报错,因为野指针根本不知道自己究竟要把人带向何处,只能被警察发现自己就是个野指针。

所以野指针是代码中最孤独的存在,他的对象被抛弃后,如果没有人来找他的话,他的灵魂就永远在代码中飘荡,无所依靠。而我现在也就像一个野指针一样飘荡在东莞的土地上,内心的地址空空荡荡,没有人来填补我所需要去的方向。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方寸间沧海桑田

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值