C++ 设计模式(四)----原型模式

原型模式是一种创建型设计模式,它通过拷贝已有对象来创建新对象。C++中,原型模式通常使用拷贝构造函数实现,可能涉及深拷贝和浅拷贝。在含有指针成员的情况下,需要特别注意拷贝的正确性。原型模式适用于快速创建相同或类似对象,但也存在如子类需实现Clone操作的困难。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是原型模式?

          先来看个例子:每年的校园招聘的时候,许多好公司来学校招应届生,大家就要去投简历,我相信大家都是聪明人,先写好一份原始简历,拿去复印n多份,然后去参加宣讲会投简历,投完简历后,第二天发现要简历写牛B点,就去修改原始简历,然后再去打印n多份就可以了。其中原始简历就是原型模式中的原型。

          那么原型的模式意图呼之欲出:用原型实例指定创建对象的种类,并且通过拷贝(复制)这些原型创建新的对象。

          在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这这个定义中,最重要的一个词是“拷贝”,也就是口头上的复制,而这个拷贝,也就是原型模式的精髓所在。

          在c++中,怎么实现原型模式呢?实际上就拷贝构造函数,而且有时候还涉及到深拷贝,这个自行研究c++深拷贝机制。下面给出最简单的一种实现:

#include <iostream>
using namespace std;

class Prototype
{
public:
	 Prototype(){}
	 ~Prototype(){}

	 virtual Prototype *clone() = 0;
};

class ConcretePrototypeA :public Prototype
{
public:
	ConcretePrototypeA() :member(0){}
	~ConcretePrototypeA(){}

	ConcretePrototypeA(const ConcretePrototypeA &rhs)
	{
		member = rhs.member;
	}

	virtual ConcretePrototypeA* clone()
	{
		cout << "copy of self" << endl;
		return new ConcretePrototypeA(*this);
	}

private:
	int member;
};

int main(int argc, char **argv)
{
	//生成对像
	ConcretePrototypeA *conPro = new ConcretePrototypeA();

	//复制自身
	ConcretePrototypeA * conPro1 = conPro->clone();

	//复制自身
	ConcretePrototypeA * conPro2 = conPro->clone();

	delete conPro;
	conPro = NULL;

	delete conPro1;
	conPro1 = NULL;

	delete conPro2;
	conPro2 = NULL;

	return 0;
}

上述代码实现了一个最简单的原型模式,但是已经将原型模式的基本实现原理展现出来了。而有的时候,当调用Clone获得了一个复制的对象以后,需要改变对象的状态,此时就可能需要在ConcretePrototype类中添加一个Initialize操作,专门用于初始化克隆对象。由于在clone的内部调用的是复制构造函数,而此处又涉及到深复制和浅复制的问题。所以,在实际操作的过程中,这些问题,都需要进行仔细的考虑。


来看一个稍微复杂点的例子:类含有指针成员,这里就涉及到了拷贝构造函数的深拷贝。其实这里例子还需要一个拷贝复制函数,很简单,就是要考虑到自赋值的情况就可以了。

#include <iostream>
using namespace std;

class Resume
{
public:
	Resume(){}

	virtual Resume* clone() =0;
	virtual void show() {};

	virtual ~Resume(){}

protected:
	char*name;
};

class ResumeA : public Resume
{
public:

	ResumeA(){}

	ResumeA(const char *str)  //构造函数  
	{
		if (str == NULL)
		{
			name = new char[1];
			name[0] = '\0';
		}
		else
		{
			name = new char[strlen(str) + 1];
			strcpy(name, str);
		}
	}

	ResumeA(const ResumeA &rhs) //拷贝构造函数  
	{
		name = new char[strlen(rhs.name) + 1];
		strcpy(name, rhs.name);
	}
                
	ResumeA& operator=(const ResumeA& rhs)
	{
		if (this == &rhs)
			return *this;
		delete[] name;
		int len = strlen(rhs.name);
		name = new char[len + 1];
		strcpy(name, rhs.name);
		return *this;
	}

	 ResumeA* clone() override	
	{
		cout << "ResumeA name : " << name << endl;
		return new ResumeA(this->name);
	}

	 ~ResumeA()
	 {
		 delete[] name;
	 }
};

int main()
{
	Resume *r = new ResumeA("a");

	Resume *r1 = r->clone();
	 
	delete r1;
	r1 = NULL;

}


总结:

         工厂方法模式、抽象工厂模式、建造者模式和原型模式都是创建型模式。工厂方法模式适用于生产较复杂,一个工厂生产单一的一种产品的时候;抽象工厂模式适用于一个工厂生产多个相互依赖的产品;建造者模式着重于复杂对象的一步一步创建,组装产品的过程,并在创建的过程中,可以控制每一个简单对象的创建;原型模式则更强调的是从自身复制自己,创建要给和自己一模一样的对象。

         原型模式作为创建型模式中最特殊的一个模式,具体的创建过程,是由对象本身提供,这样我们在很多的场景下可以很方便的快速的构建新的对象。但是,原型模式的最大缺点是继承原型的子类都要实现Clone操作,这个是很困难的。例如,当所考虑的类已经存在时就难以新增Clone操作。当内部包括一些不支持拷贝或者有循环引用的对象时,实现克隆可能也会很困难。说以说,每一种设计模式都有它的优点和缺点,在设计的时候,我们需要进行权衡各方面的因素,扬长避短。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值