引言
原型模式意图是通过原型实例指定待构造对象的类型,通过拷贝这些原型创建新的对象。从原型模式的意图,我们可以看出原因模式的核心在通过复制原型创建新的对象,原型的作用在于确定新对象类型;从字面上理解原型模式的意图和对象的拷贝构造很接近,但是仔细分析两者还是有区别的,例如:拷贝构造发生在对象的初始创建阶段,而原型模式可以在对象的任何阶段进行复制而不限于对象的初始创建阶段。
使用场景
原型模式的核心在于通过复制原型创建新的对象,所以原型复制可以带来优势的场景也就是原型模式使用的场景了。
- 场景一:对象创建成本很高,例如:初始化时间很长,占用IO很重;
- 场景二:系统中多出存在此类型,而且每个使用环节都会给它的属性重新赋值;
- 场景三:重新创建一个新的对象很繁琐,需要复杂的创建流程。
模式实现
从原型模式的意图可以看出,每个原型实例都存在一个负责原型拷贝的接口(clone)。调用者通过调用clone实现原型对象的拷贝复制。
由于在实际系统开发过程中,原型对象的数目不固定,我们需要创建一个原型管理器管理原型对象保持一个原型对象注册表,动态的创建和销毁原型对象。
原型实现
原型声明
#pragma once
struct OfficialDocument;
typedef struct OfficialDocument OfficialDocument;
struct OfficialDocument
{
OfficialDocument* (*clone)(OfficialDocument* self);
void (*display)(OfficialDocument* self);
void (*destroy)(OfficialDocument* self);
};
OfficialDocument* createFARProtoType();
OfficialDocument* createSRSProtoType();
原型实现
#include "official_document.h"
#include <stdlib.h>
#include <stdio.h>
struct FeasibilityAnalysisReport
{
OfficialDocument officialDocument;
int feasibility;
};
typedef struct FeasibilityAnalysisReport FeasibilityAnalysisReport;
struct SoftwareRequirementsSpecification
{
OfficialDocument officialDocument;
int reqirementsNumber;
};
typedef struct SoftwareRequirementsSpecification SoftwareRequirementsSpecification;
OfficialDocument* cloneFeasibilityAnalysisReport(OfficialDocument* self)
{
FeasibilityAnalysisReport* report = (FeasibilityAnalysisReport*)self;
FeasibilityAnalysisReport* newReport = (FeasibilityAnalysisReport*)malloc(sizeof(FeasibilityAnalysisReport));
if (NULL != newReport)
{
newReport->officialDocument.clone = report->officialDocument.clone;
newReport->officialDocument.display = report->officialDocument.display;
newReport->officialDocument.destroy = report->officialDocument.destroy;
newReport->feasibility = report->feasibility;
}
return (OfficialDocument*)newReport;
}
void displayFeasibilityAnalysisReport(OfficialDocument* self)
{
FeasibilityAnalysisReport* report = (FeasibilityAnalysisReport*)self;
printf_s("FeasibilityAnalysisReport's feasibility = %d\r\n", report->feasibility);
}
void destroyFeasibilityAnalysisReport(OfficialDocument* self)
{
FeasibilityAnalysisReport* report = (FeasibilityAnalysisReport*)self;
free(report);
}
OfficialDocument* cloneSoftwareRequirementsSpecification(OfficialDocument* self)
{
SoftwareRequirementsSpecification* require = (SoftwareRequirementsSpecification*)self;
SoftwareRequirementsSpecification* newRequire = (SoftwareRequirementsSpecification*)malloc(sizeof(SoftwareRequirementsSpecification));
if (NULL != newRequire)
{
newRequire->officialDocument.clone = newRequire->officialDocument.clone;
newRequire->officialDocument.display = newRequire->officialDocument.display;
newRequire->officialDocument.destroy = newRequire->officialDocument.destroy;
newRequire->reqirementsNumber = require->reqirementsNumber;
}
return (OfficialDocument*)newRequire;
}
void displaySoftwareRequirementsSpecification(OfficialDocument* self)
{
SoftwareRequirementsSpecification* require = (SoftwareRequirementsSpecification*)self;
printf_s("SoftwareRequirementsSpecification's reqirementsNumber = %d\r\n", require->reqirementsNumber);
}
void destroySoftwareRequirementsSpecification(OfficialDocument* self)
{
SoftwareRequirementsSpecification* specification = (SoftwareRequirementsSpecification*)self;
free(specification);
}
OfficialDocument* createFARProtoType()
{
FeasibilityAnalysisReport* self = (FeasibilityAnalysisReport* )malloc (sizeof(FeasibilityAnalysisReport));
if (NULL != self)
{
self->officialDocument.clone = cloneFeasibilityAnalysisReport;
self->officialDocument.display = displayFeasibilityAnalysisReport;
self->officialDocument.destroy = destroyFeasibilityAnalysisReport;
self->feasibility = 1;
}
return (OfficialDocument*)self;
}
OfficialDocument* createSRSProtoType()
{
SoftwareRequirementsSpecification* self = (SoftwareRequirementsSpecification*)malloc(sizeof(SoftwareRequirementsSpecification));
if (NULL != self)
{
self->officialDocument.clone = cloneSoftwareRequirementsSpecification;
self->officialDocument.display = displaySoftwareRequirementsSpecification;
self->officialDocument.destroy = destroySoftwareRequirementsSpecification;
self->reqirementsNumber = 50;
}
return (OfficialDocument*)self;
}
原型管理器
管理器声明
#pragma once
#include "official_document.h"
#define SRS "SRS"
#define FAR "FAR"
struct ProtoTypeManagerAttr;
typedef struct ProtoTypeManager
{
struct ProtoTypeManagerAttr* attr;
void (*add)(struct ProtoTypeManager* self, const char* name, OfficialDocument* document);
void (*erase)(struct ProtoTypeManager* self, const char* name);
void (*init)(struct ProtoTypeManager* self);
OfficialDocument* (*acquire)(struct ProtoTypeManager* self, const char* name);
}ProtoTypeManager;
ProtoTypeManager* protoTypeManager();
void destroyProtoTypeManager(ProtoTypeManager* manager);
void destroyOfficialDocument(OfficialDocument* doc);
管理器实现
#include "proto_type_manager.h"
#include <string.h>
#include <stdlib.h>
#define MAX_MAP_LENGTH 100
typedef struct Map
{
const char* name;
OfficialDocument* doc;
}Map;
typedef struct ProtoTypeManagerAttr
{
Map maps[MAX_MAP_LENGTH];
int curr;
}ProtoTypeManagerAttr;
void init(struct ProtoTypeManager* self)
{
self->add(self, FAR, createFARProtoType());
self->add(self, SRS, createSRSProtoType());
}
void add(ProtoTypeManager* self, const char* name, OfficialDocument* document)
{
self->attr->maps[self->attr->curr].name = name;
self->attr->maps[self->attr->curr].doc = document;
self->attr->curr++;
}
void erase(ProtoTypeManager* self, const char* name)
{
int curr = self->attr->curr;
for (int i = 0; i < curr; i++)
{
if (0 == strcmp(self->attr->maps[i].name, name))
{
free(self->attr->maps[i].doc);
for (int j = i; j < curr; j++)
{
self->attr->maps[j].name = self->attr->maps[j + 1].name;
self->attr->maps[j].doc = self->attr->maps[j + 1].doc;
}
return;
}
}
}
OfficialDocument* acquire(struct ProtoTypeManager* self, const char* name)
{
int curr = self->attr->curr;
for (int i = 0; i < curr; i++)
{
if (0 == strcmp(self->attr->maps[i].name, name))
{
return self->attr->maps[i].doc;
}
}
return NULL;
}
ProtoTypeManager* protoTypeManager()
{
static ProtoTypeManagerAttr managerAttr = {
.maps = {0},
.curr = 0
};
static ProtoTypeManager manager = {
.init = init,
.add = add,
.erase = erase,
.acquire = acquire,
.attr = &managerAttr
};
return &manager;
}
void destroyProtoTypeManager(ProtoTypeManager* manager)
{
manager->erase(manager, SRS);
manager->erase(manager, FAR);
}
应用举例
#include <stdlib.h>
#include "proto_type_manager.h"
int main()
{
ProtoTypeManager* manager = protoTypeManager();
manager->init(manager);
OfficialDocument* far = manager->acquire(manager, FAR);
OfficialDocument* newFar = far->clone(far);
newFar->display(newFar);
newFar->destroy(newFar);
OfficialDocument* srs = manager->acquire(manager, SRS);
OfficialDocument* newSRS = far->clone(srs);
newSRS->display(newSRS);
newSRS->destroy(newSRS);
return 0;
}
输出结果
FeasibilityAnalysisReport's feasibility = 1
SoftwareRequirementsSpecification's reqirementsNumber = 50
总结
原型模式的目标在于通过拷贝原型对象快速创建新的对象,原型对象的类型就是新创建对象的类型。一般应用于创建成本较高且复杂繁琐的场景。