简介

原型模式(Prototype Pattern)是一种创建型设计模式,使你能够复制已有对象,而无需使代码依赖它们所属的类,同时又能保证性能。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。

如果你需要复制一些对象,同时又希望代码独立于这些对象所属的具体类,可以使用原型模式。

作用

  1. 利用已有的一个原型对象,快速地生成和原型对象一样的实例。
  2. 跳过构造函数的约束,便于提升性能。

实现步骤

  1. 创建原型接口,并声明克隆方法。
  2. 使用new运算符调用原型版本的构造函数。
  3. 将子类构造函数的直接调用,替换为对原型工厂方法的调用。

UML

Java代码

基础原型抽象类

// Shape.java 基础抽象类
public abstract class Shape implements Cloneable { private int width;
private int height;
private String color = "";
protected String type; public Shape() { } public String getType() {
return type;
} // 抽象方法,子类覆盖
public abstract void draw(); public void setWidth(int width) {
this.width = width;
} public int getWidth() {
return this.width;
} public int getHeight() {
return this.height;
} public void setHeight(int height) {
this.height = height;
} public void setColor(String color) {
this.color = color;
} public String getColor() {
return this.color;
} // 克隆方法
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
} @Override
public String toString() {
return String.format("{width = %s, height = %s, type = %s, color = %s }",
this.width, this.height, this.type, this.color);
}
}

具体原型者

// Circle.java 具体原型类,克隆方法会创建一个新对象并将其传递给构造函数。
public class Circle extends Shape {
public Circle() {
super();
type = "Circle";
} @Override
public void draw() {
System.out.println("Circle::draw() method.");
}
}
// Rectangle.java 具体原型类,克隆方法会创建一个新对象并将其传递给构造函数。
public class Rectangle extends Shape {
public Rectangle() {
super();
type = "Rectangle";
} @Override
public void draw() {
System.out.println("Rectangle::draw() method.");
}
}
// 具体原型类,克隆方法会创建一个新对象并将其传递给构造函数。
public class Square extends Shape {
public Square() {
super();
type = "Square";
} @Override
public void draw() {
System.out.println("Square::draw() method.");
}
}

客户使用类

// Application.java 客户调用方
public class Application { public List<Shape> shapes = new ArrayList<Shape>(); public Application() {
} public void addToShapes() {
Circle circle = new Circle();
circle.setWidth(10);
circle.setHeight(20);
circle.setColor("red");
shapes.add(circle); // 添加clone
Circle anotherCircle = (Circle) circle.clone();
anotherCircle.setColor("pink");
shapes.add(anotherCircle);
// 变量 `anotherCircle(另一个圆)`与 `circle(圆)`对象的内容完全一样。 Rectangle rectangle = new Rectangle();
rectangle.setWidth(99);
rectangle.setHeight(69);
rectangle.setColor("green");
shapes.add(rectangle);
// 添加clone
shapes.add((Shape) rectangle.clone());
} // 直接取出
public Shape getShape(Integer index) {
return this.shapes.get(index);
} // 取出时候clone
public Shape getShapeClone(Integer index) {
Shape shape = this.shapes.get(index);
return (Shape) shape.clone();
} public void printShapes() {
for (int i = 0; i < this.shapes.size(); i++) {
Shape shape = this.shapes.get(i);
System.out.println("shape " + i + " : " + shape.toString());
}
} }

测试调用

    /**
* 原型模式主要就是复制已有的对象,而无需实例化类,从而提升实例化对象时的性能
* 其实就是复制实例的属性到新对象上,减少了执行构造的步骤
*/
Application application = new Application();
application.addToShapes();
Shape shapeClone = application.getShapeClone(1);
// 更改clone
shapeClone.setColor("gray");
System.out.println("shapeClone : " + shapeClone.toString());
// 直接更改
application.getShape(3).setColor("yellow");
application.printShapes(); // /*********************** 分割线 ******************************************/
application.shapes.add(new Square());
for (Shape shape : application.shapes) {
shape.draw();
System.out.println(shape.toString());
}

C代码

基础原型抽象类

// func.h 基础头文件
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h> typedef struct Shape shape;
typedef struct Circle circle;
typedef struct Rectangle rectangle;
typedef struct Square square; // 定义了Shape作为基础接口,以便各形状有统一类型
typedef struct Shape
{
char name[50];
int width;
int height;
char color[50];
char category[50];
void (*draw)(struct Shape *shape);
struct Shape *(*clone)(struct Shape *shape);
char *(*to_string)(struct Shape *shape);
void (*set_width)(struct Shape *shape, int width);
int (*get_width)(struct Shape *shape);
void (*set_height)(struct Shape *shape, int height);
int (*get_height)(struct Shape *shape);
void (*set_color)(struct Shape *shape, char *color);
char *(*get_color)(struct Shape *shape);
void (*set_category)(struct Shape *shape, char *category);
char *(*get_category)(struct Shape *shape);
} Shape;
Shape *shape_constructor(char *name); typedef struct Circle
{
char name[50];
int width;
int height;
char color[50];
char category[50];
void (*draw)(struct Circle *shape);
struct Circle *(*clone)(struct Circle *shape);
char *(*to_string)(struct Circle *shape);
void (*set_width)(struct Circle *shape, int width);
int (*get_width)(struct Circle *shape);
void (*set_height)(struct Circle *shape, int height);
int (*get_height)(struct Circle *shape);
void (*set_color)(struct Circle *shape, char *color);
char *(*get_color)(struct Circle *shape);
void (*set_category)(struct Circle *shape, char *category);
char *(*get_category)(struct Circle *shape);
} Circle;
Circle *circle_constructor(char *name); typedef struct Square
{
char name[50];
int width;
int height;
char color[50];
char category[50];
void (*draw)(struct Square *shape);
struct Square *(*clone)(struct Square *shape);
char *(*to_string)(struct Square *shape);
void (*set_width)(struct Square *shape, int width);
int (*get_width)(struct Square *shape);
void (*set_height)(struct Square *shape, int height);
int (*get_height)(struct Square *shape);
void (*set_color)(struct Square *shape, char *color);
char *(*get_color)(struct Square *shape);
void (*set_category)(struct Square *shape, char *category);
char *(*get_category)(struct Square *shape);
} Square;
Square *square_constructor(char *name); typedef struct Rectangle
{
char name[50];
int width;
int height;
char color[50];
char category[50];
void (*draw)(struct Rectangle *shape);
struct Rectangle *(*clone)(struct Rectangle *shape);
char *(*string)(struct Rectangle *shape);
void (*set_width)(struct Rectangle *shape, int width);
int *(*get_width)(struct Rectangle *shape);
void (*set_height)(struct Rectangle *shape, int height);
int *(*get_height)(struct Rectangle *shape);
void (*set_color)(struct Rectangle *shape, char *color);
char *(*get_color)(struct Rectangle *shape);
void (*set_category)(struct Rectangle *shape, char *category);
char *(*get_category)(struct Rectangle *shape);
} Rectangle;
Rectangle *rectangle_constructor(char *name); // 调用客户端
typedef struct Application
{
struct Shape **shapes;
int shapes_length;
void (*add_to_shapes)(struct Application *app);
void (*add_shape)(struct Application *app, Shape *shape);
Shape *(*get_shape)(struct Application *app, int index);
Shape **(*get_shapes)(struct Application *app);
Shape *(*get_shape_clone)(struct Application *app, int index);
void (*print_shapes)(struct Application *app);
} Application;
Application *application_constructor();
// shape.c 基础类,供各种具体形状复用
#include "func.h" // shape基础抽象类,供子类继承覆盖
// C没有抽象和继承,此处作为公共类存在
void shape_draw(Shape *shape)
{
printf("\r\n Shape::draw()");
} void shape_set_width(Shape *shape, int width)
{
shape->width = width;
} int shape_get_width(Shape *shape)
{
return shape->width;
} int shape_get_height(Shape *shape)
{
return shape->height;
} void shape_set_height(Shape *shape, int height)
{
shape->height = height;
} void shape_set_color(Shape *shape, char *color)
{
strncpy(shape->color, color, 50);
} char *shape_get_color(Shape *shape)
{
return shape->color;
} void shape_set_category(Shape *shape, char *category)
{
strncpy(shape->category, category, 50);
} char *shape_get_category(Shape *shape)
{
return shape->category;
} char *shape_to_string(Shape *shape)
{
static char result[1024];
sprintf(result, "[name = %s width = %d, height = %d, category = %s, color = %s]",
shape->name, shape->width, shape->height, shape->category, shape->color);
return result;
} // 将指针指向同一内存的方式来实现clone
Shape *shape_clone(Shape *shape)
{
Shape *copy = (Shape *)malloc(sizeof(Shape));
memcpy(copy, shape, sizeof(Shape));
strcat(copy->name, "(clone)");
// printf("\r\n shape_clone: %s", copy->to_string(copy));
return copy;
} // 定义简单结构体,复制基本属性和draw函数
Shape *shape_clone2(Shape *shape)
{
struct Shape copy = {
.width = shape->width,
.height = shape->height,
};
strcpy(copy.name, shape->name);
strcat(copy.name, "[clone]");
strcpy(copy.color, shape->color);
strcpy(copy.category, shape->category);
Shape *shape_copy = &copy;
shape_copy->draw = shape->draw;
// printf("\r\n shape_clone: %s", shape->to_string(shape_copy));
return shape_copy;
} Shape *shape_constructor(char *name)
{
printf("\r\n shape_constructor() [构建Shape]");
Shape *shape = (Shape *)malloc(sizeof(Shape));
strncpy(shape->name, name, 50);
shape->draw = &shape_draw;
shape->clone = &shape_clone;
shape->to_string = &shape_to_string;
shape->set_width = &shape_set_width;
shape->get_width = &shape_get_width;
shape->set_height = &shape_set_height;
shape->get_height = &shape_get_height;
shape->set_color = &shape_set_color;
shape->get_color = &shape_get_color;
shape->set_category = &shape_set_category;
shape->get_category = &shape_get_category;
return shape;
}

具体原型者

// circle.c 具体原型类,复用父类方法,实现自己的draw函数。
#include "func.h" // 重新定义draw函数
void circle_draw(Circle *shape)
{
printf("\r\n Circle::draw()");
} Circle *circle_constructor(char *name)
{
printf("\r\n shape_constructor() [构建Circle]");
Shape *shape = (Shape *)shape_constructor(name);
Circle *circle = (Circle *)shape;
circle->draw = &circle_draw;
return circle;
}
// rectangle.c 具体原型类,复用父类方法,实现自己的draw函数。
#include "func.h" // 重新定义draw函数
void rectangle_draw(Rectangle *shape)
{
printf("\r\n Rectangle::draw()");
} Rectangle *rectangle_constructor(char *name)
{
printf("\r\n shape_constructor() [构建Rectangle]");
Shape *shape = (Shape *)shape_constructor(name);
Rectangle *rectangle = (Rectangle *)shape;
rectangle->draw = &rectangle_draw;
return rectangle;
}
// square.c 具体原型类,复用父类方法,实现自己的draw函数。
#include "func.h" // 重新定义draw函数
void square_draw(Square *shape)
{
printf("\r\n Square::draw()");
} Square *square_constructor(char *name)
{
printf("\r\n shape_constructor() [构建Square]");
Shape *shape = (Shape *)shape_constructor(name);
Square *square = (Square *)shape;
square->draw = &square_draw;
return square;
}

客户使用类

// application.c 客户调用方
#include "func.h" void app_add_to_shapes(Application *app)
{
Circle *circle = circle_constructor("circle");
circle->set_category(circle, "Circle");
circle->set_width(circle, 10);
circle->set_height(circle, 20);
circle->set_color(circle, "red");
app->add_shape(app, (Shape *)circle); // 添加Clone
Circle *another_circle = circle->clone(circle);
another_circle->set_color(another_circle, "pink");
app->add_shape(app, (Shape *)another_circle);
// 变量 `another_circle(另一个圆)`与 `circle(圆)`对象的内容完全一样。 Rectangle *rectangle = rectangle_constructor("rectangle");
rectangle->set_category(rectangle, "Rectangle");
rectangle->set_width(rectangle, 99);
rectangle->set_height(rectangle, 69);
rectangle->set_color(rectangle, "green");
app->add_shape(app, (Shape *)rectangle);
// 再添加一个clone
app->add_shape(app, (Shape *)rectangle->clone(rectangle));
} void app_add_shape(Application *app, Shape *shape)
{
app->shapes_length += 1;
Shape **new_shapes = (Shape **)calloc(app->shapes_length, sizeof(Shape));
// 复制原有数组,并追加新内容到新数组
for (int i = 0; i < app->shapes_length - 1; i++)
{
new_shapes[i] = app->shapes[i];
}
new_shapes[app->shapes_length - 1] = shape;
free(app->shapes);
// 指向新数组
app->shapes = new_shapes;
} Shape *app_get_shape(Application *app, int index)
{
return app->shapes[index];
} Shape **app_get_shapes(Application *app)
{
return app->shapes;
} Shape *app_get_shape_clone(Application *app, int index)
{
Shape *shape = app->shapes[index];
if (shape != NULL)
{
return shape->clone(shape);
}
return NULL;
} void app_print_shapes(Application *app)
{
for (int i = 0; i < app->shapes_length; i++)
{
Shape *shape = app->shapes[i];
printf("\r\n shape%d: %s", i, shape->to_string(shape));
}
} // 给观察者绑定主题,同时把观察者添加到主题列表
Application *application_constructor()
{
printf("\r\n application_constructor() [构建Application]");
Application *app = (Application *)malloc(sizeof(Application));
app->shapes_length = 0;
app->shapes = (Shape **)calloc(app->shapes_length, sizeof(Shape));
app->add_to_shapes = &app_add_to_shapes;
app->add_shape = &app_add_shape;
app->get_shape = &app_get_shape;
app->get_shapes = &app_get_shapes;
app->get_shape_clone = &app_get_shape_clone;
app->print_shapes = &app_print_shapes;
return app;
}

测试调用

#include "../src/func.h"

int main(void)
{
printf("test start:\r\n");
/**
* 原型模式主要就是复制已有的对象,而无需实例化类,从而提升实例化对象时的性能
* 其实就是复制实例的属性到新对象上,减少了执行构造的步骤。
*/
Application *application = application_constructor();
application->add_to_shapes(application);
Shape *shape_clone = application->get_shape_clone(application, 0);
// SetColor需要接口中定义
shape_clone->set_color(shape_clone, "gray");
printf("\r\n shape_clone : %s", shape_clone->to_string(shape_clone));
// 直接更改
// application->get_shape(application, 3)->set_color(application->get_shape(application, 3), "yellow");
application->print_shapes(application); /*********************** 分割线 ******************************************/
// 追加一个Squre实例,相关属性为空
application->add_shape(application, (Shape *)square_constructor("square"));
// 打不打印查看结果 for (int i = 0; i < application->shapes_length; i++)
{
Shape *shape = application->shapes[i];
shape->draw(shape);
printf("\r\n shape_%d %s", i, shape->to_string(shape));
}
}

更多语言版本

不同语言实现设计模式:https://github.com/microwind/design-pattern

【原型设计模式详解】C/Java/JS/Go/Python/TS不同语言实现的更多相关文章

  1. [ 转载 ] Java开发中的23种设计模式详解(转)

    Java开发中的23种设计模式详解(转)   设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...

  2. android java 设计模式详解 Demo

    android java 设计模式详解 最近看了一篇设计模式的文章,深得体会,在此基础我将每种设计模式的案例都写成Demo的形式,方便读者研究学习, 首先先将文章分享给大家: 设计模式(Design ...

  3. Java温故而知新(5)设计模式详解(23种)

    一.设计模式的理解 刚开始“不懂”为什么要把很简单的东西搞得那么复杂.后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“简单”就是一把钥匙开一把锁的模式,目 ...

  4. JAVA设计模式简介及六种常见设计模式详解

    一.什么是设计模式                                                                                           ...

  5. Javascript设计模式详解

    Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...

  6. Javascript常用的设计模式详解

    Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...

  7. 你不知道的JavaScript--Item15 prototype原型和原型链详解

    用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性,可以为其添加函数供实例访问,其它的就不清楚了, ...

  8. 从mixin到new和prototype:Javascript原型机制详解

    从mixin到new和prototype:Javascript原型机制详解   这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...

  9. javascript设计模式详解之策略模式

    接上篇命令模式来继续看下js设计模式中另一种常用的模式,策略模式.策略模式也是js开发中常用的一种实例,不要被这么略显深邃的名字给迷惑了.接下来我们慢慢看一下. 一.基本概念与使用场景: 基本概念:定 ...

  10. iOS中MVC等设计模式详解

    iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...

随机推荐

  1. 新的世界,我们推荐不劳而获 -> 持续更新中

    随着技术带来的生产力爆发越来越猛烈,有人提出是不是有必要保留一些落后的生产工艺及相关岗位,以避免社会动荡. 我的答案:不用.但是要改变社会对于不劳而获的态度:我们对于生活资料的不劳而获持接受的态度,但 ...

  2. SQLyog 13.1.1.0注册码证书秘钥

    注册信息: Name:(用户名随意) License Key: Professional: 8e053a86-cdd3-48ed-b5fe-94c51b3d343c Enterprise: a4668 ...

  3. Httpt请求

    在c#中常见发送http请求的方式如下 HttpWebRequest: .net 平台原生提供,这是.NET创建者最初开发用于使用HTTP请求的标准类.使用HttpWebRequest可以让开发者控制 ...

  4. WinForm中的MVC模式--MVP模式

    本文主要介绍MVC模式在WINFORM中的实现,其实砖家们都称它为MVP模式,小弟E文不太好,真的是记不住那个P怎么拼写的.. MVC模式主要解决的问题就是将表示层和业务层进行分离,在以往做WINFO ...

  5. 制作可以显示GIF动图的activeX 控件

    因为工作需要,我需要一个可以显示gif 动图的控件,用来在VBS中显示动图,结果找了半天发现根本没有这样的控件,所以只能搜集资料自己来制作一个. 下面记录一下步骤: 1. 下载 PictureEx.h ...

  6. DVWA-File Upload(文件上传)

    文件上传是很危险的漏洞,攻击者上传木马到服务器,可以获取服务器的操作权限 LOW 审计源码 <?php if( isset( $_POST[ 'Upload' ] ) ) { // 定义 文件上 ...

  7. 利用Intent在两个页面之间进行传值操作的具体实现

    不知道为什么,我本来使用的呼声最高的Bundle发送,但是我使用它会显示不出来,由于时间问题,我今天就先不找了,先放一下,先以完成任务为己任哈! 我们都清楚,我们基本上都是用的Intent实现的页面之 ...

  8. linux 镜像备份

    linux 镜像备份 使用linux虚拟机的方法 优点 镜像大小比较小 缺点 速度可能比较慢 方法 1.打开虚拟机 我用的ubuntu,读卡器连接电脑虚拟机,ubuntu一般会自动挂载 df -h # ...

  9. webgl 系列 —— 渐变三角形

    其他章节请看: webgl 系列 渐变三角形 本文通过一个渐变三角形的示例逐步分析:varying变量.合并缓冲区.图形装配.光栅化.varying 内插 绘制三个点v1 需求:绘制三个相同颜色的点, ...

  10. 68.C++中的const

      编写程序过程中,我们有时不希望改变某个变量的值.此时就可以使用关键字 const 对变量的类型加以限定. 初始化和const   因为const对象一旦创建后其值就不能再改变,所以const对象必 ...