深克隆和浅克隆
在了解原型模式前先了解一下深克隆和浅克隆
浅克隆
浅拷贝是一种对象复制方式,其中只复制对象的成员变量值,而不复制它们所指向的资源。这意味着多
个对象可能会共享相同的资源,包括动态分配的内存、文件句柄等。
深克隆
深拷贝是一种对象复制方式,其中对象的成员变量值被复制,同时资源也被复制,每个对象都有自己独
立的资源副本。这确保了对象之间的数据独立性,不会相互干扰。深拷贝通常需要手动实现拷贝构造函
数和拷贝赋值运算符。
代码验证
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
| #include <iostream> #include <cstring>
class MyClass { public: char* data;
MyClass() { data = new char[10]; for (int i = 0; i < 10; i++) { data[i] = 'A' + i; } }
MyClass(const MyClass& other, bool deepCopy) : data(nullptr) { if (deepCopy) { data = new char[10]; std::memcpy(data, other.data, 10); std::cout << "Deep copy constructor called. Each object will have its own memory.\n"; } else { data = other.data; std::cout << "Shallow copy logic used within deep copy constructor (for demonstration purposes only).\n"; } }
void print() { for (int i = 0; i < 10; i++) { std::cout << data[i]; } std::cout << std::endl; }
void printAddresses() { std::cout << "Address of data member (pointer variable): " << &data << std::endl; std::cout << "Address pointed to by data: " << static_cast<void*>(data) << std::endl; } };
int main() { MyClass obj1; obj1.printAddresses();
MyClass obj2(obj1,false); obj2.printAddresses();
std::cout << "Comparing addresses pointed to by obj1.data and obj2.data (shallow copy):\n"; std::cout << "obj1.data points to: " << static_cast<void*>(obj1.data) << std::endl; std::cout << "obj2.data points to: " << static_cast<void*>(obj2.data) << std::endl;
MyClass obj3(obj1, true); obj3.printAddresses();
std::cout << "Comparing addresses pointed to by obj1.data and obj3.data (deep copy):\n"; std::cout << "obj1.data points to: " << static_cast<void*>(obj1.data) << std::endl; std::cout << "obj3.data points to: " << static_cast<void*>(obj3.data) << std::endl; return 0; }
|
运行结果:

如果解除析构函数的注释则会报错,原因是因为浅拷贝obj2所指向的地址在obj1的析构函数里释放掉了
原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
何时使用
系统应独立于产品的创建、构成和表示。
需要在运行时指定实例化的类,例如通过动态加载。
避免创建与产品类层次平行的工厂类层次。
类的实例只能有几种不同状态组合,克隆原型比手工实例化更方便。
如何解决
通过已有的一个原型对象,快速生成与原型对象相同的实例。
类图示例

在原型模式结构中定义了一个抽象原型类,所有的Java类都继承自java.lang.Object,而Object类提供一个clone()方法,可以将一个Java对象复制一份。因此在Java中可以,直接使用Object提供的clone()方法来实现对象的克隆,Java语言中的原型模式实现很简单
举个例子
简历复制
代码实现
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
| class Resume implements Cloneable { private String name; private String sex; private String age; private String timeArea; private String company;
public Resume(String name) { this.name = name; }
public void setPersonalInfo(String sex, String age) { this.sex = sex; this.age = age; }
public void setPersonalExperience(String timeArea, String company) { this.timeArea = timeArea; this.company = company; }
public void Display() { System.out.println("Name: " + name); System.out.println("Age: " + age); System.out.println("sex: " + sex); System.out.println("timeArea: " + timeArea); System.out.println("company: " + company); }
protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
public class Prototype { public static void main(String[] args) throws CloneNotSupportedException { Resume a = new Resume("zhang3"); a.setPersonalInfo("male", "20"); a.setPersonalExperience("2004-2008", "XX公司"); Resume b = (Resume) a.clone(); b.setPersonalExperience("2004-2006", "YY"); Resume c = (Resume) a.clone(); c.setPersonalInfo("female", "28"); a.Display(); b.Display(); c.Display(); } }
|
原型模式包含如下角色
- 原型接口(Prototype Interface):定义一个用于克隆自身的接口,通常包括一个 clone() 方法。
- 具体原型类(Concrete Prototype):实现原型接口的具体类,负责实际的克隆操作。这个类需要实现 clone() 方法,通常使用浅拷贝或深拷贝来复制自身。
- 客户端(Client):使用原型实例来创建新的对象。客户端调用原型对象的 clone() 方法来创建新的对象,而不是直接使用构造函数。
模式分析
优点
缺点
- 配备克隆方法需要全面考虑类的功能,对已有类可能较难实现,特别是处理不支持串行化的间接对象或含有循环结构的引用时。
- 必须实现 Cloneable 接口。