前言
上学期学了软件工程。提了一下面向数据流的设计。我就想写一个小框架。把设计好的数据流,可以无缝地转换为java代码。并且高可扩展,天然地支持逐步细化。本来受到AOP的影响。节点我都想加个切点作用的节点。结果我发现这样写很啰嗦,无穷无尽的感觉。最后我放弃了这种方案,改用子图的方式。我觉的这可以最大程度上满足需求的变化。一般来说最高层的图最抽象。需求变化基本不会影响它。最底层的function就像组成这世界的基本元素也不怎么会变。变化的最多的是中间层,也是最一团乱麻的,如果有个类管理代码块之间的联系那岂不是很好。
复用
我们老师一直给我们灌输对扩展开放对修改关闭的思想。但有些时候修改代码又是必要的。以前我我们总说代码复用。为啥不数据复用呢?数据从刚开始一个抽象的语义到一个具体的语义其中可以复用的地方太多了。
关于定位错误
另外关于从数据流的角度定位错误。暂不考虑错误复现的问题。我们报错的位置往往和错误的原因所在的位置相去甚远。这样我们要找到错误原因就很难,要是有个管理数据流的类,这种情况可能会大为改善。如果你有一些数据运行正常。一些数据运行异常。想象一下,数据流不断分叉,最终正确和错误数据流分道扬镳的位置极可能是错误的原因所在。准确一点说是该节点以上的节点都有可能。根据这个想法就可一写一个简陋的错误定位器(本代码里没写)。
并发
并发的管理比较简单。这抽象级别的也确实做不了啥。主要想法就是越抽象的模块之间并发程度应该越高。所以我设置了一个并发等级。每进入一个节点就减一,最后就是同步的代码。并发节点之间的数据是独立的,不需要🔓。如果你想共享一些数据可以把等级设为-1,自己管理并发。对于大量数据推荐用Java8的并发流
代码
- 提供了两个工具类可以通过
stream()
和utils()
函数获得实例。 - 一个工具函数
toMermaid
用来可视化,把输出张贴到Typora里。红色表示有子图的节点。 StreamUtils
的pipe
函数可以串联多个Flow
。但不建议。因为违背了我纯函数的设想。还是建议通过加节点和链接串联。
package cn.lyf;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import java.util.concurrent.*;
public class Flow<T> {
final private Map<String, UnaryOperator<T>> nodes = new ConcurrentHashMap<>();
final private Map<String, List<String>> edges = new ConcurrentHashMap<>();
final private Map<String, Flow<T>> map = new ConcurrentHashMap<>();
final private Set<String> jump = new CopyOnWriteArraySet<>();
// 并发等级
final private int level;
public Flow() {
this.level = 0;
}
public Flow(int level) {
this.level = level;
}
public FlowUtils<T> utils() {
return new FlowUtils<>(this);
}
public StreamUtils<T> stream() {
return new StreamUtils<>(this);
}
// 设置处理节点
public Flow<T> setHandler(String k, UnaryOperator<T> fx) {
nodes.put(k, fx);
return this;
}
// 移除处理节点
public Flow<T> removeHandler(String k) {
nodes.remove(k);
return this;
}
// 短路处理节点
public Flow<T> shortcut(String k) {
if (jump.add(k))
return this;
else
return null;
}
// 恢复处理节点
public Flow<T> unshortcut(String k) {
if (jump.remove(k))
return this;
else
return null;
}
// 从K节点开始处理data
public void start(String k, T data) {
start(k, data, level);
}
// 用子流替换k节点
public Flow<T> map(String key, Flow<T> subFlow, UnaryOperator<T> fx) {
map(key, subFlow);
return subFlow.setHandler(key, fx);
}
// 用子流细化k节点
public Flow<T> map(String key, Flow<T> subFlow) {
map.put(key, subFlow);
UnaryOperator<T> fx = nodes.get(key);
if (fx != null) {
subFlow.setHandler(key, fx);
for (String to : edges.getOrDefault(key, new ArrayList<>())) {
subFlow.link(key, to);
subFlow.map.put(to, this);
}
}
return this;
}
// 移除子流
public Flow<T> removemap(String key) {
map.remove(key);
return this;
}
// 链接from和to节点
public Flow<T> link(String from, String to) {
List<String> l = edges.get(from);
if (l == null) {
l = new CopyOnWriteArrayList<>();
edges.put(from, l);
}
if (l.add(to))
return this;
return null;
}
// 断开from和to节点链接
public Flow<T> unlink(String from, String to) {
List<String> l = edges.get(from);
if (l != null && l.remove(to))
return this;
return null;
}
// 以等级d从K节点开始处理data
private void start(String k, T data, int d) {
if (!jump.contains(k)) {
Flow<T> subFlow = map.get(k);
if (subFlow != null) {
// 不会生成多余的线程
subFlow.start(k, data, d - 1);
return;
}
UnaryOperator<T> fx = nodes.get(k);
if (fx == null)
return;
data = fx.apply(data);
if (data == null)
return;
}
if (d < 0) {
for (String v : edges.getOrDefault(k, new ArrayList<>())) {
// start(v, DeepCopy.copy(data), d - 1);
start(v, data, d - 1);
}
} else {
final T msg = data;
for (String v : edges.getOrDefault(k, new ArrayList<>())) {
new Thread(new Runnable() {
@Override
public void run() {
start(v, DeepCopy.copy(msg), d - 1);
}
}).start();
}
}
}
/*
* 绘制Mermaid图像
*/
public synchronized void toMermaid(String[] starts) {
System.out.println("```mermaid");
System.out.println("graph TD");
System.out.println("classDef black fill:#222,color:#fff,stroke:#000,stroke-width:2px;");
System.out.println("classDef red fill:#f22,color:#fff,stroke:#000,stroke-width:2px;");
for (String s : starts)
toMermaid(null, s);
System.out.println("```");
}
private void toMermaid(String f, String s) {
System.out.println(s + "(('" + s + "'))");
System.out.println("class " + s + " " + (map.get(s) == null ? "black" : "red"));
if (f != null)
System.out.println(f + "-->" + s);
List<String> ns = edges.get(s);
if (ns == null)
return;
for (String next : ns)
toMermaid(s, next);
}
/*
* 简化操作的工具包
*/
static class FlowUtils<T> {
private String last;
final private Flow<T> flow;
public FlowUtils<T> print() {
return setHandler(i -> {
System.out.println(i);
return i;
});
}
public FlowUtils(Flow<T> flow) {
this.flow = flow;
}
public FlowUtils<T> start(String k, Consumer<T> fx) {
return start(k, voidable(fx));
}
public FlowUtils<T> start(String k, Supplier<T> fx) {
return start(k, voidable(fx));
}
public FlowUtils<T> start(String k, Runnable fx) {
return start(k, voidable(fx));
}
public FlowUtils<T> start(String k, UnaryOperator<T> fx) {
flow.setHandler(k, fx);
return start(k);
}
public FlowUtils<T> start(String k) {
last = k;
return this;
}
public FlowUtils<T> link(String k) {
flow.link(last, k);
last = k;
return this;
}
public FlowUtils<T> link(String k, Consumer<T> fx) {
return link(k, voidable(fx));
}
public FlowUtils<T> link(String k, Supplier<T> fx) {
return link(k, voidable(fx));
}
public FlowUtils<T> link(String k, Runnable fx) {
return link(k, voidable(fx));
}
public FlowUtils<T> link(String k, UnaryOperator<T> fx) {
flow.setHandler(k, fx);
return link(k);
}
public FlowUtils<T> setHandler(Consumer<T> fx) {
return setHandler(voidable(fx));
}
public FlowUtils<T> setHandler(Supplier<T> fx) {
return setHandler(voidable(fx));
}
public FlowUtils<T> setHandler(Runnable fx) {
return setHandler(voidable(fx));
}
public FlowUtils<T> setHandler(UnaryOperator<T> fx) {
String[] ss = last.split("-");
int n = 0;
if (ss.length == 2)
n = Integer.valueOf(ss[1]) + 1;
String k = ss[0] + "-" + n;
return link(k, fx);
}
public FlowUtils<T> map(Flow<T> f) {
flow.map(last, f);
return this;
}
// T->void
private UnaryOperator<T> voidable(Consumer<T> fx) {
return new UnaryOperator<T>() {
public T apply(T t) {
fx.accept(t);
return t;
};
};
}
// void->T
private UnaryOperator<T> voidable(Supplier<T> fx) {
return new UnaryOperator<T>() {
public T apply(T t) {
return fx.get();
};
};
}
// void->void
private UnaryOperator<T> voidable(Runnable fx) {
return new UnaryOperator<T>() {
public T apply(T t) {
fx.run();
return t;
};
};
}
}
/*
* 流操作工具包
*/
static class StreamUtils<T> {
private Stream<T> stream;
final private Flow<T> flow;
public StreamUtils(Flow<T> flow) {
this.flow = flow;
}
public StreamUtils<T> batch(Stream<T> dataStream, String k) {
dataStream.forEach(d -> flow.start(k, d));
return this;
}
public StreamUtils<T> pipe(String k) {
return pipe(stream, k);
}
public StreamUtils<T> pipe(Stream<T> dataStream, String k) {
stream = dataStream.map(d -> {
// 取消并发,以便于修改data
flow.start(k, d, -1);
return d;
});
return this;
}
public List<T> collect() {
return stream.collect(Collectors.toList());
}
}
}