# PlaneProgram **Repository Path**: taotaohaoshuai/PlaneProgram ## Basic Information - **Project Name**: PlaneProgram - **Description**: 面向平面编程 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-11-22 - **Last Updated**: 2021-11-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [TOC] # PlaneProgram 面向平面编程 ## 1.介绍 ### 1.1 目标 ```txt 1.提高程序阅读性 2.快速理解程序逻辑 ``` ### 1.2解决的问题、目标、程序设计 ​ 一、很多程序逻辑的调用非常的深,比如方法一层层的调用,就会增加程序阅读的复杂度。而且随着阅读的代码越多,进入的方法层数越多,则就需要更强的记忆力,花费额外的时间去帮助记忆。 ​ 二、程序员在学习新技术、或者是新业务时,都需要去阅读他人的程序。面对成千上万行的程序代码,即使有丰富的注释,也需要花费很多的时间,才能将整个程序的结构以及细节了解清楚。而面向平面编程可以将所有的注释,按照程序的结构进行组装(还是在程序不运行的情况下)。由此,你可以想象到,程序生成的逻辑就像一篇作文,你只需要阅读完,就清除了解到整个程序的所有逻辑及细节。如果需要立马去优化这段程序,你也知道该去处理哪段程序。而不需要通读完所有程序,才敢下手。 ​ 三、面向平面编程,其实是将每段程序都看成一个代码块。比如:当你突然发现成千上万行的程序突然运行缓慢时,你需要去定位具体影响性能的地方时,这可能就会对你造成困扰。而面向平面编程,只需要很简单的写一个代码块代理类(计算程序运行时间),注册后,再运行这段程序,你就能看到所有代码块运行的时间。也就可以直接定位到问题。 ​ 面向平面编程的设计:如同xy轴坐标图,y轴即:从上到下展示程序执行顺序,x轴即:从左至右展示程序执行结构,比如分支、循环。同时利用函数式编程,将代码块用Lamda书写,使程序结构简化。 ​ ### 1.2 maven依赖 ```xml io.gitee.fpzhan PlaneProgram 1.0.0 ``` ## 2.代码块三要素 ### 2.1代码块 **任意行数的代码都可以写成一个代码块。** ***关于代码块大小的建议:能用一句话表达清楚代码块的大致逻辑,不要太抽象,也不要太简单。*** 代码块的定义如下: ```java /** *代码块的定义,入参为Param对象,无出参。可以将返回的参数放入Param,即可在别的代码块中取出,并使用。 *Param 对象内维护了一个Map集合,可以把他当Map对象来使用。 *key:参数名 value:具体的参数对象 */ @FunctionalInterface public interface CodeBlockFunction extends Serializable { Param apply(Param param) throws Exception; } ``` ### 2.2 参数 **每个代码块,都必须标记参数的变化。** 参数变化必然符合以下三种情况: ​ 1.删除参数 ​ 2.新增参数 ​ 3.无新增无删除 ***代码块的具体参数为什么重要?*** ​ 因为程序本质就是数据的处理,通过对数据的操作,来达到目标。而一段程序中,某个变量何时新增,何时删除,与代码块一起绑定。便能帮助代码阅读者,快速定位阅读范围。别忘了,平面编程的目的,就是为了提高程序的阅读性! ***如何知道每个代码块,修改了哪些变量?*** 有一个内置的代码块代理,变量变化监控代码块代理类。通过对比入参前后,对象字节的变化,标记出当前代码块变化的参数。 ### 2.3 注释 ​ 平面编程的目的,就是提高程序阅读性。所以注释是必不可少的。 ​ **每个代码块,都必须写对应的注释。** ​ 平面编程,最后会按照整个程序的结构,将注释组装起来。直接阅读程序的完整逻辑。 ## 3.效果展示 ### 3.1代码示例 ```java import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.serializer.SerializerFeature; import RunFlow; import RunResult; import PlaneProgramManager; import Params; import fpzhan.plane.program.test.school.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ProcessTest4 { public static RunFlow createFlow() throws Exception { Map map = new HashMap<>(); map.put("class", new AClass("1", "1")); RunFlow runFlow = PlaneProgramManager.createFlow("studentFlow"); runFlow.initParam(map).add("class").comment("初始化参数为,一年级一班信息") .flowBegin() .execute(Params.get(ClassInfos::new).add("classInfo")).comment("创建【班级基础信息】") .execute(param -> param.put("schoolName", "实验小学")).lose().add("schoolName").comment("设置【学校名称】") .execute(Params.get(ArrayList::new).add("women")).comment("创建【班级女生集合】") .execute(Params.get(ArrayList::new).add("men")).comment("创建【班级男生集合】") .execute(Params.get("class", AClass.class).then(Query::teacherByClass).add("teachers")).comment("查询并设置【班级所有老师】") .loop("teachers", "teacher").comment("遍历获取每个老师,分管学生") .execute(Params.get("teacher", Teacher.class).then(Query::studentByTeacher).add("teacherStudents")).comment("查询老师所有学生") .loop("teacherStudents", "student").comment("遍历老师的所有学生,并放入不同性别的的学生集合中") .branch().comment("判断性别") .ifs(Params.judege("student", Student.class).then(Student::isMan).compare(Object::equals, true)).comment("如果是男生") .execute(Params.get("men", List.class).updateLink(List::add, "student")).comment("将当前学生信息放入【班级男生集合】") .exitIfs() .defaults().comment("如果是女生") .execute(Params.get("women", List.class).updateLink(List::add, "student")).comment("将当前学生信息放入【班级女生集合】") .exitDefaults() .branchEnd() .loopEnd() .loopEnd() .execute( Params.get("classInfo", ClassInfos.class) .updateLink(ClassInfos::setTeachers, "teachers") .updateLink(ClassInfos::setMen, "men") .updateLink(ClassInfos::setWomen, "women") ).comment("将【班级老师】、【班级男生】、【班级女生】放入【班级信息】中") .flowEnd(); return runFlow; } public static void main(String[] args) throws Exception { //创建流程 RunFlow runFlow = createFlow(); //不用运行流程,就可以打印流程结构 System.out.println(JSON.toJSONString(runFlow.struct(), SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat)); //运行流程 RunResult result = runFlow.run(); //获取流程结果并打印 Map data = result.getData(); System.out.println(result.getData().toString()); //获取流程代理结果 JSONArray proxyResult = result.getProxyResult(); } } ``` ### 3.2 生成注释 ```json [{ "Comment": "初始化参数为,一年级一班信息" }, { "Comment": "创建【班级基础信息】" }, { "Comment": "创建【班级女生集合】" }, { "Comment": "创建【班级男生集合】" }, { "Comment": "查询并设置【班级所有老师】" }, { "Comment": "遍历获取每个老师,分管学生", "Loop-flow": [{ "Comment": "查询老师所有学生" }, { "Comment": "遍历老师的所有学生,并放入不同性别的的学生集合中", "Loop-flow": [{ "Comment": "判断性别", "Branch-1": { "Comment": "如果是男生", "Flow": [{ "Comment": "将当前学生信息放入【班级男生集合】" }] }, "Branch-2": { "Comment": "如果是女生", "Flow": [{ "Comment": "将当前学生信息放入【班级女生集合】" }] } }] } ] }, { "Comment": "将【班级老师】、【班级男生】、【班级女生】放入【班级信息】中" } ] ``` ## 4.流程 API ### 4.1 流程创建 ```java /*创建流程名称为studentFlow的代码流*/ RunFlow runFlow = PlaneProgramManager.createFlow("studentFlow"); ``` ### 4.2 初始化流程参数 ```java //参数 Map map = new HashMap<>(); /*初始化流程参数*/ runFlow.initParam(map) ``` ### 4.3 创建流程 ```java /*创建流程*/ /*创建流程可以创建多个部分,flowBegin不传参,默认为当前流程第一部分*/ runFlow.flowBegin() .flowEnd(); ``` ### 4.4 创建分组流程 ```java /*创建流程第一部分*/ runFlow.flowBegin() .flowEnd(); /*创建流程第四部分*/ runFlow.flowBegin(3) .flowEnd(); /*创建流程第二部分*/ runFlow.flowBegin(1) .flowEnd(); /*创建流程第三部分*/ runFlow.flowBegin(2) .flowEnd(); /*四个部分,会按照flowBegin内的参数,按照顺序组装。flowBegin(),默认值为0*/ ``` ### 4.5 执行顺序结构 代码示例: ```java runFlow .flowBegin() .execute(param -> param).none().comment("对参数无改动") .execute(param -> param.put("var",new ArrayList<>())).addc("var").comment("添加var变量") .execute(param -> param.remove("var")).losec("var").comment("删除var变量") .flowEnd(); ``` 注释结构: ```json [{ "Comment": "对参数无改动" }, { "Comment": "添加var变量" }, { "Comment": "删除var变量" } ] ``` ### 4.6 执行循环结构 代码示例: ```java runFlow .flowBegin() .execute(param -> param.put("list", Arrays.asList(new String[]{"ONE"}))).addc("list").comment("添加list变量") .loop("list","element").comment("循环list变量") .execute(param -> System.out.println(param.get("element"))).none().comment("打印元素") .loopEnd() .flowEnd(); ``` 注释结构: ```json [{ "Comment": "添加list变量" }, { "Comment": "循环list变量", "Loop-flow": [{ "Comment": "打印元素" }] } ] ``` ### 4.7 执行分支结构 代码示例: ``` runFlow .flowBegin() .execute(param -> param.put("isDelicious",true)).addc("isDelicious").comment("评价") .branch().comment("判断是否美味") .ifs(param -> param.get("isDelicious",Boolean.class)).comment("美味") .execute(param -> System.out.println("很好吃!")).none().comment("夸奖") .exitIfs() .defaults().comment("不美味") .execute(param -> System.out.println("不好吃!")).none().comment("批评") .exitDefaults() .branchEnd() .flowEnd(); ``` 注释结构: ```json [{ "Comment": "评价" }, { "Comment": "判断是否美味", "Branch-1": { "Comment": "美味", "Flow": [{ "Comment": "夸奖" }] }, "Branch-2": { "Comment": "不美味", "Flow": [{ "Comment": "批评" }] } } ] ``` ### 4.8 运行流程 ```java /*运行流程*/ RunResult result = runFlow.run(); /*获取流程结果*/ Map data = result.getData(); /*流程代理结果*/ JSONArray proxyResult = result.getProxyResult(); ```