【原型设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

news2024/12/23 20:31:10

简介

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

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

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

作用

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

实现步骤

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

UML

prototype-pattern.png

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/462506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IT项目管理之软件测试

1. 定义 软件测试是使用人工或者自动的手段来运行或者测定某个软件系统的过程&#xff0c;其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别。 在软件投入使用前&#xff0c;要经过一系列的严格测试&#xff0c;才能保证交付质量。 2. QC & QA &a…

会声会影导入视频是黑色的 会声会影导入视频只有声音

会声会影是一款功能很成熟的视频编辑软件&#xff0c;其友好的界面设计能照顾到初学者的需求&#xff0c;同时配置的强大功能可满足进阶者的需要。不过由于或硬件或软件的原因&#xff0c;可能会出现会声会影导入视频是黑色的&#xff0c;会声会影导入视频只有声音的问题。本文…

Docker的实际应用

一、 数据持久化 我们什么情况下要做数据持久化呢&#xff1f; 一定是在做容器之前先预判好哪些文件是要永久存储的&#xff0c; 而不会跟着它容器的一个生命周期而消失。 比如说配置文件、 日志文件、 缓存文件或者应用数据等等。 数据初始化有三种类型。 第一种 volumes&…

浏览器缓存策略:强缓存和协商缓存

浏览器缓存&#xff1a;其实就是在本地使用的计算机中开辟一个内存区&#xff0c;同时也开辟一个硬盘区&#xff0c;作为数据传输的缓冲区&#xff0c;然后利用这个缓冲区来暂时保护用户以前访问的信息通常浏览器的缓存策略分为两种&#xff1a;强缓存和协商缓存&#xff0c;强…

Vmware 搭建 Bitnami GitLab CE

Vmware 搭建 Bitnami GitLab CE 下载 Bitnami GitLab CE导入到 Vmwaressh 登录到虚拟机获取 root 用户密码访问 GitLab CE关机命令扩展磁盘配置 tls 证书安装 GitLab Runner注册 GitLab Runner其他&#xff0c;配置 docker 信任自签名证书 下载 Bitnami GitLab CE 下载地址&am…

Photoshop如何使用基础功能?

文章目录 0.引言1.菜单栏2.工具箱 0.引言 笔者从开始科研时就接触过Photoshop&#xff08;PS&#xff09;&#xff0c;这么多年一直用着感觉有些陌生&#xff0c;在每次使用PS时总感觉有些抵触&#xff0c;这状态说明还未入门。为了入门PS&#xff0c;笔者从头熟悉PS的菜单和工…

一文弄懂Jupyter的配置与使用(呕心沥血版)

Jupyter 是一个基于 Web 的交互式计算平台&#xff0c;使用户能够创建和共享文档&#xff0c;这些文档包含实时代码、方程式、可视化图表和解释文字。Jupyter 在数据分析领域被广泛应用&#xff0c;它提供了一个直观、交互式的操作界面&#xff0c;使得用户能够更容易地探索数据…

MybatisPlus入门和分页和条件查询里面的条件和null值的处理方式和查询投影和查询条件设置

MybatisPlus 简化了mybatis之前的在springboot整合MyBatis时需要自己写sql语句在接口中&#xff0c;现在只需要让接口继承BaseMapper<实体类>&#xff0c;然后在测试类中接口.增删改查方法&#xff08;&#xff09;即可 不用像springboot整合mybatis一样勾选spring web…

【Python】【进阶篇】9、Django路由系统精讲

目录 Django路由系统精讲1. Django 路由系统应用1&#xff09;配置第一个URL实现页面访问2&#xff09;正则与正则分组使用3&#xff09;正则捕获组使用 2. path()与re_path() Django路由系统精讲 在《URL是什么》一节中&#xff0c;我们对 URL 有了基本的认识&#xff0c;在本…

易基因:禾本科植物群落的病毒组丰度/组成与人为管理/植物多样性变化的相关性 | 宏病毒组

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 现代农业通过简化生态系统、引入新宿主物种和减少作物遗传多样性来影响植物病毒的出现。因此&#xff0c;更好理解农业生态中种植和未种植群落中的病毒分布&#xff0c;以及它们之间的病…

解析Mybaits核心配置文件属性

目录 1.environment 2.transactionManager 3.dataSource 4.peoperties 5.mapper 先来看看mybatis核心配置文件代码 <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN&qu…

02- stable diffusion的基本使用

stable diffusion的基本使用 对应视频 https://www.bilibili.com/video/BV1Q14y1f7XJ/https://www.bilibili.com/video/BV1av4y1E74C/ 一、下载 1.1 官方github&#xff1a; 官方github&#xff1a; GitHub - Stability-AI/stablediffusion: High-Resolution Image Synth…

Linux进程命令

目录 前言 基本命令 PS命令 语法 字段解释 栗子 top命令 语法 参数解释 栗子 kill命令 语法 参数解释 栗子 前言 进程是正在执行的一个程序或命令&#xff0c;每一个进程都是一个运行的实体&#xff0c;都有自己的地 址空间&#xff0c;并占用一定的系统资源。 基本命…

滑动奇异频谱分析:数据驱动的非平稳信号分解工具(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

线程池四种拒绝机制 实现 及执行日志

目录 目录 目录 创建线程池 测试代码 运行线程 全量代码 日志 AbortPolicy 报出异常模式 DiscardPolicy 放弃机制啥也不处理 DiscardOldestPolicy 放弃机制&#xff0c;放弃列队最早进入的 CallerRunsPolicy 交给主线程执行 创建线程池 public static ExecutorServi…

这篇文带你从入门级开始学习网络安全—认识网络安全

随着网络安全被列为国家安全战略的一部分&#xff0c;这个曾经细分的领域发展提速了不少&#xff0c;除了一些传统安全厂商以外&#xff0c;一些互联网大厂也都纷纷加码了在这一块的投入&#xff0c;随之而来的吸引了越来越多的新鲜血液不断涌入。不同于Java、C/C等后端开发岗位…

【Vue】Vue 前端设计模式梳理

文章目录 一、什么是设计模式&#xff1f;二、设计几个原则三、常见的设计模式及实际案例【1】单例模式1. 什么是单例模式&#xff1f;2.Vue中的单例模式 【2】工厂模式1. 什么是工厂模式&#xff1f;2.Vue中的工厂模式 【3】策略模式1. 什么是策略模式&#xff1f;2.策略模式的…

2023年6月CDGP数据治理专家认证报名及费用

目前6月DAMA-CDGP数据治理认证考试开放报名地区有&#xff1a;北京、上海、广州、深圳、长沙、呼和浩特。 目前南京、济南、西安、杭州等地区还在接近开考人数中&#xff0c;打算参加6月考试的朋友们可以抓紧时间报名啦&#xff01;&#xff01;&#xff01; DAMA认证为数据管…

密码基础知识(3)---对称密码体制

目录 一、对称密码概念 二、别名 三、对称密码体制的优缺点&#xff1a; 1、对称密码体制的缺点&#xff1a; 2、对称密码体制的优点&#xff1a; 四、对称密码的分类 1、序列密码 2、分组密码 五、分组密码的分组模式 1、ECB模式:Electronic CodeBook mode(电子密码…

Node【Node.js 20】新特性

文章目录 &#x1f31f;前言&#x1f31f;Node.js 20: 一次重要的升级和改进&#x1f31f;Internationalization API Update&#x1f31f;端口管理器&#x1f31f;字符串处理&#x1f31f; 更好的调试工具&#x1f31f; Crypto模块的更新&#x1f31f;总结&#x1f31f;写在最后…