今天这一章说的是,要改变我们日常编码的思维习惯,回归到它的本质——数据。
所有的程序,就是在处理一个输入信息,然后产生输出,当然,有的程序虽然没有返回值,但是依旧对数据进行了转换。
所以,程序就是对数据的转换。
但是,我们现在很多时候都会被其他东西占据了注意力,比如、技术选型、表设计、类、算法……
面向数据编程
假如我们想要得到某个目录底下行数最多的五个文件的名字,我们会得到这样一条命令:
find . -type f | xargs wc -l | sort -n | tail -6 | head -5
find . -type f 表示从当前目录获取所有类型的文章
xargs wc -l 计算行数输出
sort -n 正序排序
tail -6 输出结果的最后6行(因为最后一行会显示左右文件的总行数,所以也稍微做一些调整)
head -5 输入结果的前5行
上面这个例子里的数据流向是很清晰的:
目录名称
→ 文件列表
→ 带有行数的列表
→ 排序后的列表
→ 最后的五个文件+总数
→ 最后的五个
可以说完全是自解释的,而且,其中的每一步的功能都可以很方便地复用。
然后,作者用Elixir语言写了另一个例子,例子本身我也不放上来了。但是例子中提到了一个操作符|> ,想特别说明一下。
管道操作符
|>是一个管道操作符:
它的作用是把它左边的值作为右边函数的第一个参数传入,所以下面两种写法等价。
"vinyl" |> String.codepoints |> Comb.subsets()
Comb.subsets(String.codepoints("vinyl"))
不是所有的语言都支持这种操作符,但是作者说,不用把它当做一种语言的特性,而应该把它当做一种不同的思考方式,一种设计哲学。就像面向对象之于过程式变成一样。
面向数据的好处
说到面向对象,今天这个主题也是要革面向对象的命的。
使用面向对象的编程思路,我们会习惯于讲数据隐藏起来,封装起来。然后对象之间互相改变状态,这也是很多耦合发生的原因。
上面的那个例子,如果用面向对象的方式来写,下面的例子,可以当一个伪代码来看,就是简单做个示例。
List<File> getMax5LineCountFiles(String path)List<File> files =getFiles(path);
for(File file :files){
int lineCount=FileUtil.countLine(file);
file.setLineCount(lineCount);
}
files.sort(Comparator.comparing(File::getLineCount));
return files.subList(files.getSize()-5-1,files.getSize()-1);
}
很显然的是,这个方法没有太多的复用空间,顶多是获取文件行数这个方法可以复用一下。
而且,为了让这个示例简单一点点,我直接把行数写进了File类里,实际上这个类里可能并没有这个字段属性,我需要用一些其他方式,来保存文件与行数的对应,比如一个Map,Map<Integer,File>,如果这样用的话,排序也会麻烦一些,要自己写比较器。
总之,不论实现麻不麻烦,最重要的是,它们是耦合的。
改用数据流的方式,可让数据从封装中解放出来。
让程序遵循 数据->代码->数据->
今天先说这些,明天把补充后半部分,大家晚安~