原型模式

原型模式是一种创建型设计模式,其核心思想是通过复制已有对象(原型)来创建新对象,而非通过构造函数从头初始化。这种模式能有效减少重复初始化的开销,尤其适用于创建复杂对象或大量相似对象的场景。本文将从核心结构、多语言实现、优缺点、使用场景等维度全面解析原型模式。

一、原型模式核心结构

原型模式的核心包含两个关键角色,同时需重点区分浅拷贝与深拷贝,这是原型模式的核心要点:

1.1 核心角色

  • 抽象原型(Prototype):定义克隆自身的接口,通常包含一个Clone方法,声明对象拷贝的规范,是所有具体原型的公共约束。

  • 具体原型(Concrete Prototype):实现抽象原型的Clone方法,完成自身的拷贝逻辑,根据需求实现浅拷贝或深拷贝。

1.2 核心概念:浅拷贝与深拷贝

原型模式的核心差异的在于拷贝的深度,直接决定新旧对象的独立性:

  • 浅拷贝:仅复制对象本身及基本类型成员,引用类型成员(如指针、对象引用)仅复制引用地址,新旧对象共享同一引用对象,一方修改会影响另一方。

  • 深拷贝:完全复制对象及所有嵌套的引用类型成员,为每个引用类型成员重新分配内存并复制内容,新旧对象相互独立,修改互不影响。

二、多语言实现原型模式

不同语言因语法特性、内置工具差异,原型模式的实现方式各有侧重,以下结合C#、Python、Golang、C++、纯C五种语言,实现统一场景(拷贝包含引用类型成员的Person对象),清晰展示深浅拷贝的实现逻辑。

2.1 C# 实现(内置接口+序列化)

C# 内置ICloneable接口作为抽象原型,通过MemberwiseClone实现浅拷贝,深拷贝可借助序列化快速实现,无需手动处理嵌套引用,适配面向对象开发场景。

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
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

// 抽象原型接口(复用系统内置ICloneable,简化开发)
public interface IPrototype : ICloneable { }

// 具体原型(包含引用类型成员)
[Serializable] // 深拷贝需添加序列化标记,否则无法序列化引用类型
public class Person : IPrototype
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; } // 引用类型成员(嵌套对象)

// 浅拷贝实现:调用系统内置方法,仅拷贝值类型和引用地址
public object Clone()
{
return this.MemberwiseClone(); // 内置浅拷贝方法,高效简洁
}

// 深拷贝实现:通过二进制序列化/反序列化,自动处理嵌套引用
public Person DeepClone()
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, this); // 序列化对象
ms.Position = 0; // 重置流位置
return (Person)formatter.Deserialize(ms); // 反序列化生成新对象
}
}
}

// 引用类型成员(需同步添加序列化标记)
[Serializable]
public class Address
{
public string City { get; set; }
public string Street { get; set; }
}

// 测试代码(验证深浅拷贝效果)
class Program
{
static void Main()
{
// 初始化原型对象
var prototype = new Person
{
Name = "张三",
Age = 25,
Address = new Address { City = "北京", Street = "朝阳路" }
};

// 浅拷贝测试
var shallowCopy = (Person)prototype.Clone();
shallowCopy.Address.City = "上海"; // 修改引用成员
Console.WriteLine($"浅拷贝后原型地址:{prototype.Address.City}"); // 输出:上海(原型受影响)

// 深拷贝测试
var deepCopy = prototype.DeepClone();
deepCopy.Address.City = "广州"; // 修改引用成员
Console.WriteLine($"深拷贝后原型地址:{prototype.Address.City}"); // 输出:上海(原型不受影响)
}
}

2.2 Python 实现(内置copy模块)

Python 遵循“鸭子类型”,无需显式定义抽象原型接口,copy模块内置copy()(浅拷贝)和deepcopy()(深拷贝)方法,可直接复用,大幅简化代码,适配快速开发场景。

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
import copy

# 引用类型:地址类
class Address:
def __init__(self, city, street):
self.city = city
self.street = street

# 具体原型类:人员类
class Person:
def __init__(self, name, age, address):
self.name = name # 基本类型
self.age = age # 基本类型
self.address = address # 引用类型成员

# 浅拷贝方法:复用copy模块
def shallow_clone(self):
return copy.copy(self)

# 深拷贝方法:复用copy模块,自动处理嵌套引用
def deep_clone(self):
return copy.deepcopy(self)

# 测试代码
if __name__ == "__main__":
# 初始化原型对象
prototype = Person("张三", 25, Address("北京", "朝阳路"))

# 浅拷贝验证
shallow_copy = prototype.shallow_clone()
shallow_copy.address.city = "上海"
print(f"浅拷贝后原型地址:{prototype.address.city}") # 输出:上海

# 深拷贝验证
deep_copy = prototype.deep_clone()
deep_copy.address.city = "广州"
print(f"深拷贝后原型地址:{prototype.address.city}") # 输出:上海

2.3 Golang 实现(结构体方法+序列化)

Golang 无类和继承,通过结构体模拟原型,浅拷贝可通过结构体值传递实现,深拷贝可借助JSON序列化实现通用逻辑,兼顾简洁性与性能,符合Go语言极简设计哲学。

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
package main

import (
coding/json"
fmt"
)

// 引用类型:地址结构体
type Address struct {
y string
et string
}

// 具体原型:人员结构体
type Person struct {
e string
Age int
*Address // 指针类型(引用类型)
}

// 浅拷贝:结构体值传递,指针成员仅复制地址
func (p *Person) ShallowClone() *Person {
e := *p // 值拷贝,指针成员仍指向原地址
eturn &clone
}

// 深拷贝:通过JSON序列化/反序列化,通用且无需手动处理嵌套
func (p *Person) DeepClone() (*Person, error) {
序列化原对象
data, err := json.Marshal(p)
r != nil {
eturn nil, err
序列化生成新对象
r clone Person
ern.Unmarshal(data, &clone)
f err != nil {
return nil, err
turn &clone, nil
}

func main() {
/ 初始化原型对象
prototype := &Person{
Name: "张三",
ge: 25,
ddress: &Address{
City: "北京",
treet: "朝阳路",
}

/ 浅拷贝测试
shallowCopy := prototype.ShallowClone()
shallowCopy.Address.City = "上海"
fmt.Printf("浅拷贝后原型地址:%s\n", prototype.Address.City) // 输出:上海

/ 深拷贝测试
pCopy, _ := prototype.DeepClone()
deepCopy.Address.City = "广州"
fmt.Printf("深拷贝后原型地址:%s\n", prototype.Address.City) // 输出:上海
}
dee / / },
S A A / }
re ir = jso va}
// 反 r if er // r clonAddress Nam Stre Cit " "en

2.4 C++ 实现(拷贝构造函数)

C++ 通过拷贝构造函数实现原型模式,默认拷贝构造为浅拷贝,深拷贝需手动重载拷贝构造函数或自定义克隆方法,需注意内存管理,避免内存泄漏,适配高性能底层开发场景。

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 <string>
using namespace std;

// 引用类型:地址类
class Address {
public:
string city;
string street;
// 构造函数
Address(string c, string s) : city(c), street(s) {}
};

// 具体原型:人员类
class Person {
private:
string name;
int age;
Address* address; // 指针(引用类型)
public:
// 构造函数
Person(string n, int a, Address* addr) : name(n), age(a), address(addr) {}

// 浅拷贝构造函数(默认行为,仅复制指针)
Person(const Person& other) {
this->name = other.name;
this->age = other.age;
this->address = other.address; // 共享指针,浅拷贝
}

// 深拷贝方法:手动创建新的引用对象,实现完全拷贝
Person* DeepClone() {
Address* newAddr = new Address(this->address->city, this->address->street);
return new Person(this->name, this->age, newAddr);
}

// 析构函数:释放内存,避免泄漏
~Person() {
delete address;
}

// 辅助方法:修改地址城市
void setCity(string c) {
this->address->city = c;
}

// 辅助方法:获取地址城市
string getCity() {
return this->address->city;
}
};

// 测试代码
int main() {
// 初始化原型对象
Address* addr = new Address("北京", "朝阳路");
Person* prototype = new Person("张三", 25, addr);

// 浅拷贝测试
Person shallowCopy = *prototype; // 调用浅拷贝构造函数
shallowCopy.setCity("上海");
cout << "浅拷贝后原型地址:" << prototype->getCity() << endl; // 输出:上海

// 深拷贝测试
Person* deepCopy = prototype->DeepClone();
deepCopy->setCity("广州");
cout << "深拷贝后原型地址:" << prototype->getCity() << endl; // 输出:上海

// 释放内存
delete prototype;
delete deepCopy;
return 0;
}

2.5 纯C语言实现(结构体+函数模拟)

纯C语言无面向对象特性,通过结构体封装数据,函数模拟克隆行为,深浅拷贝均需手动处理指针和内存分配,代码冗余但底层可控,适配嵌入式、底层开发场景。

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 引用类型:地址结构体
typedef struct {
char* city;
char* street;
} Address;

// 具体原型:人员结构体
typedef struct {
char* name;
int age;
Address* address;
} Person;

// 工具函数:初始化Address
Address* address_init(const char* city, const char* street) {
Address* addr = (Address*)malloc(sizeof(Address));
addr->city = (char*)malloc(strlen(city) + 1);
strcpy(addr->city, city);
addr->street = (char*)malloc(strlen(street) + 1);
strcpy(addr->street, street);
return addr;
}

// 工具函数:初始化Person
Person* person_init(const char* name, int age, Address* addr) {
Person* p = (Person*)malloc(sizeof(Person));
p->name = (char*)malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
p->address = addr;
return p;
}

// 浅拷贝函数:仅复制结构体,共享指针成员
Person* person_shallow_clone(Person* p) {
Person* clone = (Person*)malloc(sizeof(Person));
clone->name = p->name; // 共享字符串指针
clone->age = p->age; // 复制基本类型
clone->address = p->address; // 共享Address指针
return clone;
}

// 深拷贝函数:手动复制所有指针成员,分配新内存
Person* person_deep_clone(Person* p) {
// 深拷贝Address
Address* newAddr = (Address*)malloc(sizeof(Address));
newAddr->city = (char*)malloc(strlen(p->address->city) + 1);
strcpy(newAddr->city, p->address->city);
newAddr->street = (char*)malloc(strlen(p->address->street) + 1);
strcpy(newAddr->street, p->address->street);

// 深拷贝Person
Person* clone = (Person*)malloc(sizeof(Person));
clone->name = (char*)malloc(strlen(p->name) + 1);
strcpy(clone->name, p->name);
clone->age = p->age;
clone->address = newAddr;
return clone;
}

// 工具函数:释放Person内存
void person_free(Person* p) {
free(p->name);
free(p->address->city);
free(p->address->street);
free(p->address);
free(p);
}

// 测试代码
int main() {
// 初始化原型对象
Address* addr = address_init("北京", "朝阳路");
Person* prototype = person_init("张三", 25, addr);

// 浅拷贝测试
Person* shallowCopy = person_shallow_clone(prototype);
// 修改浅拷贝对象的引用成员(需先释放原内存,避免内存泄漏)
free(shallowCopy->address->city);
shallowCopy->address->city = (char*)malloc(strlen("上海") + 1);
strcpy(shallowCopy->address->city, "上海");
printf("浅拷贝后原型地址:%s\n", prototype->address->city); // 输出:上海

// 深拷贝测试
Person* deepCopy = person_deep_clone(prototype);
free(deepCopy->address->city);
deepCopy->address->city = (char*)malloc(strlen("广州") + 1);
strcpy(deepCopy->address->city, "广州");
printf("深拷贝后原型地址:%s\n", prototype->address->city); // 输出:上海

// 释放内存
person_free(prototype);
free(shallowCopy); // 浅拷贝仅释放结构体,不释放共享指针
person_free(deepCopy);

return 0;
}

三、原型模式的优缺点

原型模式的价值与局限均围绕“拷贝替代创建”的核心逻辑,需结合场景权衡使用,避免过度设计。

3.1 核心优点

  • 降低对象创建开销:对于初始化成本高的对象(如数据库连接、大文件解析、复杂计算对象),拷贝比重新初始化更高效,减少重复操作。

  • 简化对象创建逻辑:无需关注构造函数的参数、访问权限等限制,直接复制已有原型对象,降低创建复杂度,提升开发效率。

  • 支持动态扩展:可在运行时动态修改原型对象,生成不同变体的新对象,无需修改原有代码,符合“开闭原则”。

  • 保护原型状态:深拷贝可保留原型对象的初始状态,新对象的修改不会影响原型,适用于需要基准模板的场景。

3.2 主要缺点

  • 深拷贝实现复杂:嵌套引用类型越多,深拷贝逻辑越繁琐,易出现内存泄漏(如C/C++)、循环引用(如Python)等问题,增加开发难度。

  • 维护成本较高:当原型对象的属性或结构发生变更时,需同步修改拷贝逻辑(尤其是深拷贝),否则会出现拷贝不完整的问题。

  • 性能损耗差异:深拷贝涉及大量内存复制,在高频拷贝、大对象拷贝场景下,性能损耗明显高于浅拷贝和直接创建。

  • 非面向对象语言适配差:纯C等无面向对象特性的语言,需手动模拟原型结构和拷贝逻辑,代码冗余度高,维护不便。

四、原型模式的使用场景

原型模式的核心适用场景是“对象创建成本高、需批量生成相似对象”,同时需根据引用类型的存在与否,选择浅拷贝或深拷贝。

  • 对象创建成本高:如创建包含大量数据的缓存对象、需频繁读取文件/数据库的配置对象、经过复杂计算初始化的对象。

  • 批量生成相似对象:如游戏中的角色、粒子系统、NPC,电商系统中的批量订单,仅属性略有差异,通过拷贝原型可快速生成。

  • 动态生成对象变体:如根据模板生成不同主题的UI组件、不同配置的接口请求对象,无需重复编写初始化逻辑。

  • 避免构造函数耦合:当对象构造逻辑复杂,且创建逻辑需与业务逻辑隔离时,拷贝原型可降低代码耦合度。

  • 浅拷贝适用场景:对象无引用类型成员,或引用成员为只读数据、无需独立修改,追求拷贝效率。

  • 深拷贝适用场景:对象包含嵌套引用类型,且新旧对象需完全独立(如多线程操作、对象修改不影响原型、需保留基准状态)。

典型实战案例

  • 设计工具的“复制粘贴”功能(如PS图层、Axure组件),本质是原型模式的浅拷贝/深拷贝应用;

  • 数据库连接池中的连接对象克隆,避免频繁创建/关闭连接,提升数据库访问性能;

  • 序列化/反序列化场景(如JSON、二进制序列化),核心是深拷贝的实现,用于对象传输、持久化;

  • 游戏开发中的角色实例生成,通过原型拷贝快速创建大量相似角色,仅修改属性(如血量、攻击力)。

五、总结

原型模式以“拷贝替代创建”为核心,核心价值在于平衡对象创建的性能与复杂度,其核心难点是深浅拷贝的选择与实现。不同语言的实现方式,反映了语言本身的设计理念和适用场景:

  • 高级面向对象语言(C#、Python):提供内置工具(接口、模块)简化拷贝逻辑,深拷贝可通过序列化快速实现,开发效率高;

  • 静态语言(Golang):通过结构体方法+序列化实现通用拷贝,兼顾简洁性与性能,贴合语言极简特性;

  • 编译型语言(C++):需手动管理拷贝构造函数和内存,深拷贝实现灵活但易出错,适配高性能底层开发;

  • 纯C语言:通过结构体+函数模拟原型模式,代码冗余但底层可控,适用于嵌入式等资源受限场景。

在工程实践中,原型模式并非万能,需注意:浅拷贝虽高效但存在数据共享风险,深拷贝虽安全但性能开销较高;当对象结构简单、创建成本低时,直接使用构造函数更简洁。原型模式可与工厂模式、单例模式协同使用(如单例管理原型对象,工厂负责克隆分发),最大化发挥其价值,成为优化复杂对象创建流程的重要工具。