# 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();
```