OJ在线评测系统 后端 判题机模块预开发 架构分析 使用工厂模式搭建

news2024/11/16 4:49:57

判题机模块预开发(架构师)(工厂模式)

判题机模块

是为了把代码交个代码沙箱去处理 得到结果返回

代码沙箱

梳理判题模块和代码沙箱的关系

判题模块:调用代码沙箱 把代码和输入交给代码沙箱去执行

代码沙箱:只负责接受代码和输入 返回编译的结果 不负责判题

这两个模块完全解耦

我们采用API交互

为什么代码沙箱要接受和输出一组运行用例

前提:我们的每道题目有多组测试用例

如果每个用例单独调用一个代码用例 会调用多次接口 需要多次网络运输 程序要多次编译 记录程序的执行状态 重复的代码不重复编译

这是一种常见的性能优化的方法

创建一个新的包

用来放代码沙箱模块

先写一个接口

package com.dduo.dduoj.judge.codesandbox;

public interface CodeSandbox {

    ExecuteCodeRequest executeCode(ExecuteCodeRequest executeCodeRequest);
}

提高通用性

之后我们的项目代码只调用接口

不调用具体的实现类

就不用去修改名称了 便于拓展

写一下实体类

ExecuteCodeRequest请求

package com.dduo.dduoj.judge.codesandbox.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExecuteCodeRequest {
    private List<String> inputList;
    private String code;
    private String language;
}


ExecuteCodeResponse响应

package com.dduo.dduoj.judge.codesandbox.model;

import com.dduo.dduoj.model.dto.question.JudgeConfig;
import com.dduo.dduoj.model.dto.questionsubmit.JudgeInfo;

import java.util.List;

public class ExecuteCodeResponse {
    private List<String> outputList;

    //执行信息
    private String message;

    //执行状态
    private Integer status;

    private JudgeInfo judgeInfo;
}

完善

定义不同的代码沙箱实现类

示例代码沙箱

远程代码沙箱

第三方代码沙箱

架构工作

lombok Builder注解

测试一下

package com.dduo.dduoj.judge.codesandbox;

import com.dduo.dduoj.judge.codesandbox.impl.ExampleCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.RemoteCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;

import com.dduo.dduoj.model.enums.QuestionSubmitLanguageEnum;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Arrays;
import java.util.List;


@SpringBootTest
class CodeSandboxTest {
    @Test
    void executeCode() {
        CodeSandbox codeSandbox = new RemoteCodeSandbox();
        String code = "int main() { }";
        String language = QuestionSubmitLanguageEnum.JAVA.getValue();
        List<String> inputList = Arrays.asList("1 2", "3 4");
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .language(language)
                .inputList(inputList)
                .build();
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
        Assertions.assertNotNull(executeCodeResponse);
    }
}

工厂模式

但是现在问题是我们把new代码沙箱写死了 如果后面项目要改用其他沙箱

可能要改很多地方的代码

我们要使用工厂模式

根据用具传入的字符串参数 生成对应的代码沙箱实现类

package com.dduo.dduoj.judge.codesandbox;


import com.dduo.dduoj.judge.codesandbox.impl.ExampleCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.RemoteCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.ThirdPartyCodeSandbox;

//代码沙箱工厂 根据字符串参数 创建指定的代码沙箱示例
public class CodeSandboxFactory {

    /*
     * 创建代码沙箱示例
     * @param type 沙箱类型
     * @return
     * */
    public static CodeSandbox NewInstance(String type) {
        switch (type) {
            case "example":
                return new ExampleCodeSandbox();
            case "remote":
                return new RemoteCodeSandbox();
            case "thirdParty":
                return new ThirdPartyCodeSandbox();
            default:
                return new ExampleCodeSandbox();
        }
    }
}

如果确定代码沙箱示例不会出现线程安全问题

可复用

那么可以使用单例工厂模式

但是这种方式是不可取的 我们应该把这些东西放到配置里面

配置化 去改配置文件 而不是修改字符串

这就叫参数配置化 开发者只需要去修改配置文件 而不是去看项目代码 就能自定义使用项目的更多功能

先在application.yml里面去设置

再在程序里面去读取

示例

package com.dduo.dduoj.judge.codesandbox;

import com.dduo.dduoj.judge.codesandbox.impl.ExampleCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.RemoteCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;

import com.dduo.dduoj.model.enums.QuestionSubmitLanguageEnum;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Arrays;
import java.util.List;


@SpringBootTest
class CodeSandboxTest {

    @Value("${codesandbox.type:example}")
    private String value;

    @Test
    void executeCode() {
        CodeSandbox codeSandbox = CodeSandboxFactory.NewInstance(value);
        String code = "int main() { }";
        String language = QuestionSubmitLanguageEnum.JAVA.getValue();
        List<String> inputList = Arrays.asList("1 2", "3 4");
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .language(language)
                .inputList(inputList)
                .build();
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
        Assertions.assertNotNull(executeCodeResponse);
    }
}

我们要增强代码沙箱的能力

在调用代码沙箱前 输出请求参数 在代码沙箱调用后 输出响应结果日志

package com.dduo.dduoj.judge.codesandbox.impl;

import com.dduo.dduoj.judge.codesandbox.CodeSandbox;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;
import lombok.extern.slf4j.Slf4j;

//示例代码沙箱 (仅供测试 跑通业务流程)
@Slf4j
public class ExampleCodeSandbox implements CodeSandbox {
    @Override
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        log.info("请求信息"+executeCodeRequest.toString());
        System.out.println("示例代码沙箱");
        return null;
    }
}

思考

我们每一个代码沙箱类都写一个 log.info ?

难道每次调用代码沙箱前后都要执行log ?

我们使用代理模式 提供一个Proxy 来增强代码沙箱的能力

静态代理模式

中介

调用者调用代理类 代理类去调用代码沙箱

代理类还可以做一些额外的功能

不仅不用改变原本的代码沙箱实现类 而且对调用者来说 基本也没有改变

也不需要在每一个调用代码沙箱的地方去统计代码

package com.dduo.dduoj.judge.codesandbox;


import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@AllArgsConstructor
public class CodeSandboxProxy implements CodeSandbox{
    private CodeSandbox codeSandbox;
    
    @Override
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        log.info("代码沙箱的请求信息"+executeCodeRequest.toString());
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
        log.info("代码沙箱的响应信息"+executeCodeResponse.toString());
        return executeCodeResponse;
    }
}

接下来我们就可以去修改调用方式

@Test
void executeCodeByProxy() {
    CodeSandbox codeSandbox = CodeSandboxFactory.NewInstance(value);
    codeSandbox =new CodeSandboxProxy(codeSandbox);
    String code = "int main() { }";
    String language = QuestionSubmitLanguageEnum.JAVA.getValue();
    List<String> inputList = Arrays.asList("1 2", "3 4");
    ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
            .code(code)
            .language(language)
            .inputList(inputList)
            .build();
    ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
    Assertions.assertNotNull(executeCodeResponse);
}

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

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

相关文章

mat (Eclipse Memory Analyzer Tool)使用以及详解

前言 在Java开发中&#xff0c;内存问题往往不易被发现&#xff0c;但它们可能导致应用性能下降甚至崩溃。Eclipse Memory Analyzer Tool&#xff08;MAT&#xff09;是一个强大的开源工具&#xff0c;专门用于分析Java堆转储&#xff08;heap dumps&#xff09;文件&#xff…

【含文档】基于Springboot+Vue的高校竞赛管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 系统定义了三个…

2024四川省赛 The 2024 Sichuan Provincial Collegiate Programming Contest补题记录

B - Link Summon(补) 题意 每一组样例给定五个数字&#xff0c;分别对应1 2 3 4 5的数量&#xff0c;问能凑出多少个6(每个数字都可以当对应数字或者1使用) 思路 由于数字的数量固定&#xff0c;所以为了尽可能凑出多个6&#xff0c;贪心优先选择数量最少的数字配对方式 首…

【移植】标准系统方案之瑞芯微RK3568移植案例(二)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… Camera 基本概念 OpenHarmony 相机驱动框架模型对上实现相机 HDI …

Windows安装Vim,并在PowerShell中直接使用vim

大家好啊&#xff0c;我是豆小匠。 这期介绍下怎么在windows的PowerShell上使用vim&#xff0c;方便在命令行里修改配置文件等。 先上效果图&#xff1a; 1、下载Vim GitHub传送门&#xff1a;https://github.com/vim/vim-win32-installer/releases 选择win-64的版本下载即可&…

【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器

文章目录 C list 容器详解&#xff1a;从入门到精通前言第一章&#xff1a;C list 容器简介1.1 C STL 容器概述1.2 list 的特点 第二章&#xff1a;list 的构造方法2.1 常见构造函数2.1.1 示例&#xff1a;不同构造方法2.1.2 相关文档 第三章&#xff1a;list 迭代器的使用3.1 …

[大语言模型] 情感认知在大型语言模型中的近期进展-2024-09-26

[大语言模型] 情感认知在大型语言模型中的近期进展-2024-09-26 论文信息 Title: Recent Advancement of Emotion Cognition in Large Language Models Authors: Yuyan Chen, Yanghua Xiao https://arxiv.org/abs/2409.13354 情感认知在大型语言模型中的近期进展 《Recent A…

ElasticSearch安装分词器与整合SpringBoot

ElasticSearch安装分词器与整合SpringBoot 如果还没安装的点击安装ElasticSearch查看怎么安装 分词器 1.分词器 在Elasticsearch中&#xff0c;分词器&#xff08;Tokenizer&#xff09;是分析器&#xff08;Analyzer&#xff09;的一部分&#xff0c;它的主要职责是将文本输入…

MySql简介及发展

MySql简介及发展 1、MySql起源和分支 MySQL 是最流行的关系型数据库软件之一&#xff0c;由于其体积小、速度快、开源免费、简单易用、维护成本 低等&#xff0c;在集群架构中易于扩展、高可用&#xff0c;因此深受开发者和企业的欢迎。 Oracle和MySQL是世界市场占比最高的两…

C#图像处理学习笔记(屏幕截取,打开保存图像、旋转图像、黑白、马赛克、降低亮度、浮雕)

1、创建Form窗体应用程序 打开VS&#xff0c;创建新项目-语言选择C#-Window窗体应用&#xff08;.NET Framework) 如果找不到&#xff0c;检查一下有没有安装.NET 桌面开发模块&#xff0c;如果没有&#xff0c;需要下载&#xff0c;记得勾选相关开发工具 接上一步&#xff0c;…

【ARM 嵌入式 编译系列 10.4 -- GNU Binary Utilies】

文章目录 GNU Binary Utilities 详细介绍常用工具介绍1. arm-none-eabi-objcopy2. arm-none-eabi-readelf3. arm-none-eabi-size4. arm-none-eabi-objdump5. arm-none-eabi-nm6. arm-none-eabi-strip7. arm-none-eabi-ld8. arm-none-eabi-as9. arm-none-eabi-addr2line10. arm-…

linux内核双向链表使用list klist

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、list和klist是什么&#xff1f;二、代码示例1.list2.klist 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; linux内核中大量使…

Spring Boot打造甘肃非遗文化传承网站

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本甘肃非物质文化网站就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信…

如何像专家一样修复任何 iPhone 上的“iPhone 已禁用”错误

“我忘记了密码&#xff0c;并且我的 iPhone 在多次输入错误密码后就被禁用了&#xff0c;如何再次访问我的手机&#xff1f;” 作为最安全的数字设备之一&#xff0c;iPhone 必须使用正确的密码解锁。即使您可以使用 Face ID 或 Touch ID 访问您的设备&#xff0c;在充电或重…

交警车辆通入城行证管理建设方案和必要性-———未来之窗行业应用跨平台架构

一、系统目标 建立一个高效、便捷、规范的车辆入城通行证管理系统&#xff0c;提高交警部门的管理效率&#xff0c;优化城市交通流量&#xff0c;减少交通拥堵&#xff0c;保障城市交通安全。 二、系统功能模块 1. 通行证申请模块 - 提供在线申请入口&#xff0c;申请人填…

【MySQL】聚合函数、group by子句

目录 聚合函数 count([distinct] column) sum([distinct] column) avg([distinct] column) max([distinct] column) min([distinct] column) group by子句 1.如何显示每个部门的平均薪资和最高薪资 2.显示每个部门每种岗位的平均薪资和最低薪资 3.显示平均工资低于200…

maven给springboot项目打成jar包 maven springboot打包配置

基于maven的spring boot 打包分离依赖及配置文件 使用springCloud或springboot的过程中&#xff0c;发布到生产环境的网速受限&#xff0c;如果每次将60,70M甚至更大的jar包上传&#xff0c;速度太慢了&#xff0c;采取jar包和配置文件分离的方式可以极大的压缩jar包大小&#…

npm 安装newman时idealTree:vue: sill idealTree buildDeps卡住了(实测成功)

删除 C:\Users\{账户}\ 文件夹中的 .npmrc 文件在命令提示符里执行 npm cache verify 在命令提示符里执行 npm config set registry https://registry.npmmirror.com 切换淘宝源来源&#xff1a; https://blog.csdn.net/weixin_39245942/article/details/135748323

【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL62

序列发生器 描述 编写一个模块&#xff0c;实现循环输出序列001011。 模块的接口信号图如下&#xff1a; 要求使用Verilog HDL实现&#xff0c;并编写testbench验证模块的功能。 输入描述&#xff1a; clk&#xff1a;时钟信号 rst_n&#xff1a;复位信号&#xff0c;低电平…

【学习笔记】手写 Tomcat 七

目录 一、优化 Dao 1. 设置 UserDaoImpl 为单例模式 2. 创建 Dao 工厂 3. 在 Service 层获取 UserDao 的实例 二、优化 Service 1. 设置 UserServiceImpl 为单例模式 2. 创建 Service 工厂 3. 在 Servlet 层获取 Service 实现类的对象 三、优化 Servlet 1. 使用配置…