遇见设计模式——工厂模式、代理模式、策略模式
记录做项目时所使用到的设计模式
工厂模式
需求:项目中定义了多种不同的代码沙箱
分别是:
- 示例代码沙箱:跑通流程的测试方法。
- 本地代码沙箱:自己实现方法。
- 第三方代码沙箱:调用网上别人的方法API。
为什么要使用工厂模式?
因为我们把 new 某个代码沙箱的代码写死了,如果后面项目要改用其他代码沙箱,可能要改很多地方的代码。
使用工厂模式,根据用户传入的字符串参数(代码沙箱类别),来生成对应的实现类
此处使用静态工厂模式,实现比较简单,符合我们的需求。
/**
* 代码沙箱创建工厂(静态工厂模式)
* 根据字符串参数
*
* @author Judy
* @create 2023-10-11-16:51
*/
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();
}
}
}
代理模式
需求:在调用代码沙箱前,输出请求参数日志;在代码沙箱调用后,输出响应结果日志,便于管理员去分析。
不可能每个代码沙箱类都写一遍log.info
、每次调用代码沙箱前后都执行 log、
为什么要使用代理模式?
使用代理模式,提供一个 Proxy
,来增强代码沙箱的能力(代理模式的作用就是增强能力)
-
原本:需要用户自己去调用多次。
-
使用代理后:不仅不用改变原本的代码沙箱实现类,而且对调用者来说,调用方式几乎没有改变,也不需要在每个调用沙箱的地方去写统计代码。
/**
* 代理模式
* @author Judy
* @create 2023-10-11-17:28
*/
@Slf4j
public class CodeSandboxProxy implements CodeSandbox {
private final CodeSandbox codeSandbox;
// 也可以使用全参构造函数注解@AllArgsConstructor
public CodeSandboxProxy(CodeSandbox codeSandbox) {
this.codeSandbox = codeSandbox;
}
@Override
public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
log.info("执行前(请求信息):"+executeCodeRequest);
ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
log.info("执行后(响应信息):"+executeCodeResponse);
return executeCodeResponse;
}
}
策略模式
需求:判题策略可能会有很多种。
比如:我们的代码沙箱本身执行程序需要消耗时间,这个时间可能不同的编程语言是不同的,比如沙箱执行 Java 程序要额外花 10 秒。
为什么要使用策略模式?
针对不同的情况,定义独立的策略,便于分别修改策略和维护。而不是把所有的判题逻辑、if ... else ...
代码全部混在一起写。
- 定义判题策略接口,让代码更加通用化
/**
* 判题策略
*/
public interface JudgeStrategy {
/**
* 执行判题
* @param judgeContext
* @return
*/
JudgeInfo doJudge(JudgeContext judgeContext);
}
- 定义
JudgeManager
目的是尽量简化对判题功能的调用,让调用方写最少的代码、调用最简单。对于判题策略的选取,也是在JudgeManager
里处理的。
示例代码如下
/**
* 判题管理(简化调用)
*/
@Service
public class JudgeManager {
/**
* 执行判题
*
* @param judgeContext
* @return
*/
JudgeInfo doJudge(JudgeContext judgeContext) {
QuestionSubmit questionSubmit = judgeContext.getQuestionSubmit();
//获取语言类型
String language = questionSubmit.getLanguage();
JudgeStrategy judgeStrategy = new DefaultJudgeStrategy();
if ("java".equals(language)) {
judgeStrategy = new JavaLanguageJudgeStrategy();
}
if ("js".equals(language)) {
judgeStrategy = new JSLanguageJudgeStrategy();
}
if ("cpp".equals(language)) {
judgeStrategy = new CPPLanguageJudgeStrategy();
}
// 继续判断提交的语言,创建对应语言的判题策略
return judgeStrategy.doJudge(judgeContext);
}
}
修改后在实现类中的调用:
@Resource
private JudgeManager judgeManager;
//------------------------------------
//👇工厂模式
CodeSandboxFactory codeSandboxFactory = new CodeSandboxFactory();
CodeSandbox codeSandbox = codeSandboxFactory.newInstance(type);
//👇代理模式
codeSandbox = new CodeSandboxProxy(codeSandbox);
ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
//👇策略模式
JudgeInfo judgeInfo = judgeManager.doJudge(judgeContext);