Java函数式编程——通过行为参数化传递代码
日新月异的需求
作为程序员,有一个很常见的问题是,同样的东西,用户的需求会经常改变
像我们之前找苹果的例子,需求经常变在动,如果都实现,那不得累死我们程序员?
如何应对多变的需求
- 这里展示一个案例,并且逐步改善
- 筛选绿苹果
- 如果需求变成筛选红苹果,那我们需要拷贝这个方法,把Green换成Red。这样就违反了DRY
- 我们可以把颜色作为参数
- 仅仅改变颜色,把颜色传递进去,可以省去一个方法
此时又有新的需求:要区分重的苹果和轻的苹果:
行为参数化
- 经过上面的案例,我们需要一种更好的方式来应对变化的需求。
- 建模如下:你考虑的是苹果,需要根据Apple的某些属性,返回一个满足条件的boolean值。
- 我们称之为谓词,定义接口如下
可以使用ApplePredicate的多个实现来执行不同的行为
这些实现,就是不同的筛选条件,算法就是 ApplePredicate。怎么去利用这种不同的实现呢?需要filterApples方法接受ApplePredicate对象,对Apple做条件测试。那么现在就来修改之前的代码:
现在你把filterApples方法迭代集合的逻辑与你要应用到集合中每个元素的行为(这里是一个谓词)区分开了。
对于多个无用的代码,把匿名内部类更改为Lambda表达式就行
- 新需求,对苹果进行遍历,然后对其进行格式化输出
- 这个需求需要定义一个新的方法,prettyPrintApple,整体的执行框架如下
- ???就是我们要填充的部分:输入一个Apple,然后输出一个String,来定义一个接口 FormatApple
prettyPrintApple 就可以实现了,如下
- 这样就可以表示多种行为了
- 到这里,我们可以将类、匿名类、Lambda进行行为参数化,替代了之前的案例中的值参数化。
- 现在我们发现上述的ApplePredicate只能处理Apple,且filterApples也只能处理Apple,所以我们将这部分使用泛型进行抽象化,如下
- 其他的行为参数化案例
- 对集合进行排序,根据苹果颜色排序或者根据大小排序
- 在Java 8中,List自带了一个sort方法(也可选择Collections.sort)排序
- sort的行为可以用java.util.Comparator对象来参数化,它的接口如下
你可以随时创建Comparator的实现,用sort方法表现出不同的行为。比如,你可以使用匿名类,按照重量升序对库存排序
Lambda表达式
小结
- 行为参数化,就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不同行为的能力。
- 行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。
- 传递代码,就是将新行为作为参数传递给方法。但在Java 8之前这实现起来很啰嗦,在Java 8之前可以用匿名类来减少。
- Java API包含很多可以用不同行为进行参数化的方法,包括排序、线程和GUI处理。