一、原型模式
原型模式是一种创建型设计模式,其功能为复制一个运行时的对 象,包括对象各个成员当前的值。而代码又能保持独立性。用原型实例 指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
主要解决在运行期简历与删除原型。
二、何时选择使用
- 当一个系统应该独立于它的产品创建,构成和表示时。
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
三、类图
四、实现
头文件
#include<iostream>
//缺省命名
using namespace std;
1、创建抽象类---用于实现克隆函数
class Proto {
public:
Proto() { }
~Proto() { }
virtual Proto* CloneFunc() = 0;//纯虚函数
};
2、派生类实现---实现克隆函数
注意,派生类中对纯虚函数的实现时,使用了协变返回类型,稍后会补充一点协变返回类型的知识,请先看代码,阅读其逻辑
class ConreteProto :public Proto {
public:
ConreteProto(int number) {
m_number = number;
cout << "ConreteProto的有参构造被调用" << endl;
}
//拷贝构造,如果成员变量中带有指针,记得使用深拷贝
ConreteProto(const ConreteProto& conrete) {
this->m_number = conrete.m_number;
cout << "克隆后数据为:" << m_number << endl;
cout << "ConreteProto的拷贝构造函数被调用" << endl;
}
~ConreteProto() {
cout << "~ConreteProto的析构函数被调用" << endl;
}
//派生类实现,使用了协变返回类型
//抽象类中的纯虚函数为virtual Proto* CloneFunc() = 0;
ConreteProto* CloneFunc() {
cout << "CloneFunc克隆函数被执行" << endl;
cout << "正在克隆......" << endl;
cout << "克隆数据为:" << m_number << endl;
return new ConreteProto(*this);
}
private:
int m_number;
};
五、协变返回类型
协变返回类型(Covariant Return Types)是指派生类覆盖虚函数时,可以将返回类型声明为基类返回类型的派生类型。
协变返回类型允许在派生类中,覆盖虚函数并改变其返回类型。这意味着派生类可以返回一个比基类更具体的类型,而不仅限于基类的类型。
使用协变返回类型有以下几点要求和规则:
- 基类和派生类中的虚函数必须具有相同的名称、参数列表和函数签名(const 成员函数除外)。
- 派生类中的虚函数声明必须与基类中的虚函数声明匹配,包括返回类型、异常规范和常量性。
- 派生类的返回类型必须是基类返回类型的派生类型或相同类型。也就是说,派生类的返回类型必须是协变的。
协变返回类型提供了更具灵活性和易用性的代码编写方式,尤其在处理继承关系中的多态性时非常有用。它允许派生类在保持接口一致性的同时,返回更具体的类型,避免了显式的类型转换。
六、优缺
优点:
- 性能提高
- 逃避构造函数的约束
缺点:
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
- 必须实现 接口。
文章有什么错误,或者有什么不到位的地方,请各位大佬在评论区留言喔!!