对于职业规划做的好的网站,治疗早射最有效的方法是什么,网站销售方案,网络营销 网站之前的文章提到函数式编程的一等函数#xff08;First-class Function#xff09;四个性质中有“可以将过程作为返回值”这一点#xff0c;但这一点在实际使用中不如“将过程作为参数”#xff08;高阶函数#xff09;用得多。本文介绍一种这个性质用于分步函数的应用。
…之前的文章提到函数式编程的一等函数First-class Function四个性质中有“可以将过程作为返回值”这一点但这一点在实际使用中不如“将过程作为参数”高阶函数用得多。本文介绍一种这个性质用于分步函数的应用。
注意本文旨在介绍一种编程技巧希望可以给读者一点启发并非介绍某类问题的最优解实际使用还需具体问题具体分析
问题场景
相信所有人都接触过一类需求完成某个任务x这个任务x由三个步骤a、b、c组成比如一个拍照功能可能包含三个步骤1. 调起摄像头拍照2. 编辑优化照片3. 保存照片到相册。那么这类功能最简单的形式就是
class Demo{public static void main(String[] args) {taskX();}static void taskX(){//1. 执行第一步System.out.println(step 1...);//1. 执行第二步System.out.println(step 2...);//1. 执行第三步System.out.println(step 3...);}
}但是有时候我们并不要求这三个步骤一气呵成允许完成各个步骤后去做点其他事情然后再回来做剩余工作。又或者其中某个步骤在有些时候不能直接执行需要一些准备工作。比如上面所说的拍照示例中在Android平台调用摄像头得请求到摄像头权限然后保存相册还需要文件访问权限。这类行为和系统平台相关如果我们想一套代码运行于多个平台上就得分离核心功能和平台相关功能。
一种方式是直接把三个步骤写成三个子过程
class Demo {public static void main(String[] args) {TaskX.step1();System.out.println(do other task....);TaskX.step2();System.out.println(do other task2....);TaskX.step3();}
}class TaskX{static void step1() {System.out.println(step 1...);}static void step2() {System.out.println(step 1...);}static void step3() {System.out.println(step 1...);}
}但是这样相当于直接暴露三个子步骤外部可以以任意顺序调用三个步骤而且如果step2的执行依赖于step1的执行成功那么就可能引发问题需要额外的文档/注释来说明即便有了注释也没法保证安全。这里假设写TaskX模块的人与使用的人并非同一个
如果我们可以像下面这样表达一个过程
主过程1. 子过程12. 子过程23. 子过程3并且这些子过程的执行分步执行那么就可以处理这个情况了。
分步过程的实现
如果我们把一个无参无返回值的过程的类型写作() - void那么分步函数的类型是不是可以写作() - - - void表示可以分三步执行这个表示法稍微再加点元素就是() - () - () - void跟柯里化的形式很像对吧接下来就是要利用这个。
这样的过程用Scala很容易表达
val taskX () {println(step 1...)() {println(step 2...)() {println(step 3...)}}
}但是用Java我们就得写成
class Demo {public static void main(String[] args) {SupplierSupplierRunnable taskXSupplier doTaskX();SupplierRunnable step2Supplier taskXSupplier.get();//执行step1System.out.println(do other task....);Runnable step3 step2Supplier.get();//执行step2System.out.println(do other task....);step3.run();执行step3}static SupplierSupplierRunnable doTaskX() {return () - {System.out.println(step 1...);return () - {System.out.println(step 2...);return () - System.out.println(step 3...);};};}
}调用方的代码太难看我们添加几个函数式接口来稍微美化一下
class Demo {public static void main(String[] args) {Step1 step1 doTaskX();Step2 step2 step1.run();//执行step1System.out.println(do other task....);Step3 step3 step2.run();//执行step2System.out.println(do other task....);step3.run();//执行step3}static Step1 doTaskX() {return () - {System.out.println(step 1...);return () - {System.out.println(step 2...);return () - System.out.println(step 3...);};};}public interface Step1 {Step2 run();}public interface Step2 {Step3 run();}public interface Step3 extends Runnable {}
}这样每次写接口定义也挺麻烦我们可以预先定义好Step1、Step2…Step10这样写过程的时候想分几步就选择对应类型的接口。
简化分步过程的编写
如果不想定义接口我们可以编写这样一个工具MultiStepTask
class MultiStepTask {private final IteratorRunnable stepIterator;private MultiStepTask(ListRunnable stepList) {stepIterator stepList.iterator();}public static MultiStepTask create(Runnable... actions) {ListRunnable stepList Arrays.stream(actions).toList();return new MultiStepTask(stepList);}public void doNext() {if (stepIterator.hasNext()) {stepIterator.next().run();}}public void doComplete() {while (stepIterator.hasNext()) {stepIterator.next().run();}}public boolean isCompleted(){return !stepIterator.hasNext();}
}这样我们的创建分步过程的代码就变成了
static MultiStepTask taskX() {return MultiStepTask.create(() - System.out.println(step 1...),() - System.out.println(step 2...),() - System.out.println(step 3...));
}然后调用的代码就是
class Demo {public static void main(String[] args) {MultiStepTask taskX taskX();taskX.doNext();//执行step1System.out.println(do other task....);taskX.doNext();//执行step2System.out.println(do other task....);taskX.doNext();//执行step3}
}