用C语言实现原型模式

原型模式(Prototype Pattern)的核心是通过复制现有对象(原型)来创建新对象 ,避免重复初始化的开销,尤其适合创建成本高(如复杂计算、IO操作)或属性繁多的对象。在C语言中,可以通过结构体(原型对象)+ 克隆函数(复制逻辑) 实现。

C语言实现原型模式的思路

  1. 原型接口:定义一个包含"克隆函数指针"的结构体,作为所有可克隆对象的基类。
  2. 具体原型:继承原型接口,实现自己的克隆逻辑(深拷贝或浅拷贝)。
  3. 克隆操作:通过原型的克隆函数复制对象,生成新实例。

示例:文档原型(支持复制不同类型的文档)

假设需要创建多种文档(如文本文档、表格文档),每种文档有复杂属性,通过克隆原型避免重复初始化。

步骤1:定义原型接口(Prototype)

用结构体封装克隆函数,所有可克隆的对象都需包含此接口。

c 复制代码
// 原型接口:定义克隆方法
typedef struct Prototype {
    // 克隆函数:返回当前对象的副本
    struct Prototype* (*clone)(struct Prototype* self);
    // 销毁函数:释放对象内存
    void (*destroy)(struct Prototype* self);
    // 打印对象信息(方便验证)
    void (*print)(struct Prototype* self);
} Prototype;
步骤2:实现具体原型(文本文档、表格文档)

具体原型结构体"继承"原型接口,并实现克隆、销毁等方法。

2.1 文本文档(TextDocument)
c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 具体原型:文本文档
typedef struct {
    Prototype proto;       // 继承原型接口
    char title[64];        // 文档标题
    char content[1024];    // 文档内容(动态内容,需深拷贝)
    int word_count;        // 字数统计
} TextDocument;

// 文本文档的克隆方法(深拷贝:复制所有属性,包括动态内容)
static Prototype* text_clone(Prototype* self) {
    // 将原型指针转换为具体文档类型
    TextDocument* orig = (TextDocument*)self;
    // 分配新对象内存
    TextDocument* copy = (TextDocument*)malloc(sizeof(TextDocument));
    if (!copy) return NULL;
    
    // 复制原型接口(绑定相同的函数指针)
    copy->proto = orig->proto;
    
    // 深拷贝属性(字符串需逐个复制)
    strncpy(copy->title, orig->title, sizeof(copy->title)-1);
    strncpy(copy->content, orig->content, sizeof(copy->content)-1);
    copy->word_count = orig->word_count;
    
    return (Prototype*)copy; // 返回基类指针(多态)
}

// 文本文档的销毁方法
static void text_destroy(Prototype* self) {
    free(self); // 释放当前对象内存
}

// 打印文本文档信息
static void text_print(Prototype* self) {
    TextDocument* doc = (TextDocument*)self;
    printf("文本文档:\n");
    printf("标题:%s\n", doc->title);
    printf("内容:%s\n", doc->content);
    printf("字数:%d\n", doc->word_count);
}

// 初始化文本文档原型
TextDocument* text_document_create(const char* title, const char* content) {
    TextDocument* doc = (TextDocument*)malloc(sizeof(TextDocument));
    if (!doc) return NULL;
    
    // 绑定原型接口方法
    doc->proto.clone = text_clone;
    doc->proto.destroy = text_destroy;
    doc->proto.print = text_print;
    
    // 初始化属性
    strncpy(doc->title, title, sizeof(doc->title)-1);
    strncpy(doc->content, content, sizeof(doc->content)-1);
    doc->word_count = strlen(content); // 简单统计字数
    
    return doc;
}
2.2 表格文档(TableDocument)
c 复制代码
// 具体原型:表格文档(包含行列数据)
typedef struct {
    Prototype proto;       // 继承原型接口
    char title[64];        // 表格标题
    int rows;              // 行数
    int cols;              // 列数
    int** data;            // 表格数据(动态分配,需深拷贝)
} TableDocument;

// 表格文档的克隆方法(深拷贝:复制动态数组)
static Prototype* table_clone(Prototype* self) {
    TableDocument* orig = (TableDocument*)self;
    TableDocument* copy = (TableDocument*)malloc(sizeof(TableDocument));
    if (!copy) return NULL;
    
    // 复制原型接口
    copy->proto = orig->proto;
    
    // 复制基本属性
    strncpy(copy->title, orig->title, sizeof(copy->title)-1);
    copy->rows = orig->rows;
    copy->cols = orig->cols;
    
    // 深拷贝动态数组(data是二维数组,需逐个复制元素)
    copy->data = (int**)malloc(sizeof(int*) * copy->rows);
    if (!copy->data) {
        free(copy);
        return NULL;
    }
    for (int i = 0; i < copy->rows; i++) {
        copy->data[i] = (int*)malloc(sizeof(int) * copy->cols);
        if (!copy->data[i]) {
            // 内存分配失败时回滚
            for (int j = 0; j < i; j++) free(copy->data[j]);
            free(copy->data);
            free(copy);
            return NULL;
        }
        // 复制每行数据
        memcpy(copy->data[i], orig->data[i], sizeof(int) * copy->cols);
    }
    
    return (Prototype*)copy;
}

// 表格文档的销毁方法(释放动态数组)
static void table_destroy(Prototype* self) {
    TableDocument* doc = (TableDocument*)self;
    if (doc->data) {
        for (int i = 0; i < doc->rows; i++) {
            free(doc->data[i]); // 释放每行
        }
        free(doc->data); // 释放行指针数组
    }
    free(doc); // 释放对象本身
}

// 打印表格文档信息
static void table_print(Prototype* self) {
    TableDocument* doc = (TableDocument*)self;
    printf("\n表格文档:\n");
    printf("标题:%s\n", doc->title);
    printf("尺寸:%d行 %d列\n", doc->rows, doc->cols);
    printf("数据:\n");
    for (int i = 0; i < doc->rows; i++) {
        for (int j = 0; j < doc->cols; j++) {
            printf("%d ", doc->data[i][j]);
        }
        printf("\n");
    }
}

// 初始化表格文档原型
TableDocument* table_document_create(const char* title, int rows, int cols) {
    TableDocument* doc = (TableDocument*)malloc(sizeof(TableDocument));
    if (!doc) return NULL;
    
    // 绑定原型接口方法
    doc->proto.clone = table_clone;
    doc->proto.destroy = table_destroy;
    doc->proto.print = table_print;
    
    // 初始化基本属性
    strncpy(doc->title, title, sizeof(doc->title)-1);
    doc->rows = rows;
    doc->cols = cols;
    
    // 初始化动态数组(示例:填充1~rows*cols的数字)
    doc->data = (int**)malloc(sizeof(int*) * rows);
    if (!doc->data) {
        free(doc);
        return NULL;
    }
    int val = 1;
    for (int i = 0; i < rows; i++) {
        doc->data[i] = (int*)malloc(sizeof(int) * cols);
        if (!doc->data[i]) {
            // 回滚内存
            for (int j = 0; j < i; j++) free(doc->data[j]);
            free(doc->data);
            free(doc);
            return NULL;
        }
        for (int j = 0; j < cols; j++) {
            doc->data[i][j] = val++;
        }
    }
    
    return doc;
}
步骤3:使用原型模式

通过原型的clone方法复制对象,无需重新初始化。

c 复制代码
int main() {
    // 1. 创建文本文档原型
    TextDocument* text_proto = text_document_create(
        "设计模式笔记", 
        "原型模式:通过克隆创建对象..."
    );
    if (!text_proto) {
        printf("创建文本原型失败\n");
        return 1;
    }
    
    // 克隆文本原型(生成新文档)
    Prototype* text_copy = text_proto->proto.clone((Prototype*)text_proto);
    if (text_copy) {
        text_copy->print(text_copy); // 打印克隆的文本文档
        text_copy->destroy(text_copy); // 销毁克隆对象
    }
    
    // 2. 创建表格文档原型
    TableDocument* table_proto = table_document_create("数据统计", 3, 2);
    if (!table_proto) {
        printf("创建表格原型失败\n");
        text_proto->proto.destroy((Prototype*)text_proto);
        return 1;
    }
    
    // 克隆表格原型(生成新文档)
    Prototype* table_copy = table_proto->proto.clone((Prototype*)table_proto);
    if (table_copy) {
        table_copy->print(table_copy); // 打印克隆的表格文档
        table_copy->destroy(table_copy); // 销毁克隆对象
    }
    
    // 销毁原型
    text_proto->proto.destroy((Prototype*)text_proto);
    table_proto->proto.destroy((Prototype*)table_proto);
    
    return 0;
}

输出结果

复制代码
文本文档:
标题:设计模式笔记
内容:原型模式:通过克隆创建对象...
字数:23

表格文档:
标题:数据统计
尺寸:3行 2列
数据:
1 2 
3 4 
5 6 

核心要点总结

  1. 克隆逻辑 :关键是实现clone函数,根据对象属性类型选择深拷贝 (如动态分配的字符串、数组)或浅拷贝(如基本类型)。
  2. 多态性 :通过原型接口(Prototype结构体)实现多态,客户端无需关心具体原型类型,只需调用clone即可复制对象。
  3. 优势
    • 避免重复初始化的开销(如复杂计算、IO操作)。
    • 动态生成对象:运行时可通过克隆不同原型生成多种对象。
    • 简化对象创建:无需记住复杂的构造参数,直接克隆现有实例。

C语言通过结构体嵌套和函数指针模拟了原型模式的核心,适合需要频繁创建相似对象的场景(如文档编辑、游戏角色生成、配置项复制等)。

相关推荐
czy87874754 小时前
用C语言实现原型模式时,如何确定需要深拷贝还是浅拷贝?
c语言·原型模式
会飞的小新5 小时前
C 标准库之 <errno.h> 详解与深度解析
c语言·开发语言
胖咕噜的稞达鸭6 小时前
AVL树手撕,超详细图文详解
c语言·开发语言·数据结构·c++·算法·visual studio
-SGlow-6 小时前
Linux相关概念和易错知识点(48)(epoll的底层原理、epoll的工作模式、反应堆模式)
linux·服务器·c语言·网络·c++
cellurw7 小时前
Day67 Linux I²C 总线与设备驱动架构、开发流程与调试
linux·c语言·架构
无限进步_7 小时前
【C语言】在矩阵中高效查找数字的算法解析
c语言·开发语言·数据结构·c++·其他·算法·矩阵
Yupureki8 小时前
从零开始的C++学习生活 11:二叉搜索树全面解析
c语言·数据结构·c++·学习·visual studio
草莓工作室8 小时前
数据结构2:线性表1-线性表类型及其特点
c语言·数据结构
啊森要自信8 小时前
【MySQL 数据库】MySQL用户管理
android·c语言·开发语言·数据库·mysql