重拾设计模式--原型模式

文章目录

原型模式定义

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象;
核心中的核心就是 克隆clone ,后面讲

原型模式是一种创建型设计模式,它的主要意图是通过复制现有的对象实例来创建新的对象,而不是通过传统的使用构造函数来初始化创建。

原型模式UML图

优点

提高创建对象的效率:当创建一个对象的过程比较复杂,例如需要进行大量的初始化操作、读取配置文件等,如果采用传统的构造方式每次创建都要重复这些复杂过程,而原型模式通过复制已有对象,能快速创建新对象,节省时间和资源。

便于动态创建对象:可以在运行时根据已有对象动态生成新的对象,对于一些需要根据不同场景灵活生成相似对象的情况非常有用。

缺点

深拷贝和浅拷贝问题:在实现对象复制时,如果对象中包含指针等复杂成员,需要正确处理深拷贝和浅拷贝的情况,否则可能导致数据不一致等问题。比如浅拷贝只是简单复制指针,多个对象会指向同一块内存区域,修改一个对象的数据可能意外影响到其他对象。

每一个类都要配备克隆方法:要使用原型模式,需要在具体的类中实现克隆(复制)的相关方法,增加了代码编写和维护的工作量。

使用场景

对象创建成本高的情况:比如创建一个数据库连接对象,初始化过程涉及到加载驱动、配置参数、建立网络连接等复杂操作,后续需要多个相似的连接对象时,就可以用原型模式复制已有的连接对象来快速创建新的。

根据已有对象生成变体对象:例如在图形绘制系统中,已经绘制了一个圆形,要基于这个圆形生成几个大小、颜色等属性稍有不同的新圆形,通过原型模式复制已有圆形对象再进行属性修改就很方便。

C++ 代码示例

以下是一个简单的 C++ 代码示例来演示原型模式,这里假设有一个简单的 Shape(图形)类作为基类,有 Rectangle(矩形)类继承自它,通过原型模式来复制矩形对象:

cpp 复制代码
#include <iostream>
#include <string>

// 抽象基类,定义克隆接口
class Shape
{
public:
	virtual Shape* clone() = 0;
	virtual void draw() = 0;
	virtual ~Shape() {}
};

// 具体的矩形类
class Rectangle : public Shape
{
private:
	int width;
	int height;
public:
	Rectangle(int w, int h) : width(w), height(h) {}

	// 实现克隆方法,返回一个新的矩形对象副本
	Shape* clone() override 
	{
		return new Rectangle(*this);
	}

	void draw() override
	{
		std::cout << "Drawing a rectangle with width: " << width << " and height: " << height << std::endl;
	}
};

int main() 
{
	Rectangle originalRect(10, 20);
	originalRect.draw();

	// 通过原型模式复制矩形对象
	Shape* clonedRect = originalRect.clone();
	clonedRect->draw();

	delete clonedRect;
	char t;
	std::cin>>t;
	return 0;
}

在上述代码中:

首先定义了抽象基类 Shape,它有一个纯虚函数 clone 用于克隆对象,还有一个纯虚函数 draw 用于绘制图形(这里只是简单输出图形相关信息示意)。

Rectangle 类继承自 Shape,它有自己的成员变量 width 和 height 表示矩形的宽和高,其构造函数用于初始化这两个属性。关键的是实现的 clone 函数,通过 new Rectangle(this) 利用拷贝构造函数创建了一个新的 Rectangle 对象,这个新对象就是原对象的副本,然后返回这个副本的指针(以 Shape 类型返回,体现了多态性)。

在 main 函数中,先创建了一个原始的矩形对象 originalRect 并调用 draw 展示其信息,然后通过原型模式调用 clone 方法复制出一个新的矩形对象 clonedRect,同样调用 draw 展示,最后记得释放动态分配的内存(通过 delete 操作符),避免内存泄漏。

实际应用中,如果类的成员变量有指针等情况,可能还需要更细致地处理拷贝构造函数来确保深拷贝正确执行,避免出现意外的数据共享和修改问题。

深拷贝、浅拷贝

浅拷贝仅复制对象的引用(指针),而深拷贝会创建一个新对象,并复制对象的内容。

同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝.

一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题。

cpp 复制代码
class MyClass {
public:
	int* data;

	MyClass(int value) {
		data = new int(value);
	}

	// 浅拷贝构造函数
	MyClass(const MyClass& other) {
		data = other.data; // 浅拷贝,指针复制
	}

	// 析构函数
	~MyClass() {
		delete data;
	}
};

class MyClass {
public:
	int* data;

	MyClass(int value) {
		data = new int(value);
	}

	// 深拷贝构造函数
	MyClass(const MyClass& other) {
		data = new int(*(other.data)); // 深拷贝,复制对象内容
	}

	// 赋值运算符,进行深拷贝
	MyClass& operator=(const MyClass& other) {
		if (this != &other) {
			delete data;
			data = new int(*(other.data)); // 深拷贝
		}
		return *this;
	}

	// 析构函数
	~MyClass() {
		delete data;
	}
};
相关推荐
杨充16 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充16 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充16 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充16 小时前
2.面向对象的特性
设计模式
杨充16 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充16 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充16 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯19 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯1 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式