Java函数式编程——通过行为参数化传递代码

createh54个月前 (12-17)技术教程63

日新月异的需求

作为程序员,有一个很常见的问题是,同样的东西,用户的需求会经常改变

像我们之前找苹果的例子,需求经常变在动,如果都实现,那不得累死我们程序员?

如何应对多变的需求

  • 这里展示一个案例,并且逐步改善
  • 筛选绿苹果
  • 如果需求变成筛选红苹果,那我们需要拷贝这个方法,把Green换成Red。这样就违反了DRY
  • 我们可以把颜色作为参数
  • 仅仅改变颜色,把颜色传递进去,可以省去一个方法

此时又有新的需求:要区分重的苹果和轻的苹果:

行为参数化

  • 经过上面的案例,我们需要一种更好的方式来应对变化的需求。
  • 建模如下:你考虑的是苹果,需要根据Apple的某些属性,返回一个满足条件的boolean值。
  • 我们称之为谓词,定义接口如下

可以使用ApplePredicate的多个实现来执行不同的行为

这些实现,就是不同的筛选条件,算法就是 ApplePredicate。怎么去利用这种不同的实现呢?需要filterApples方法接受ApplePredicate对象,对Apple做条件测试。那么现在就来修改之前的代码:

现在你把filterApples方法迭代集合的逻辑与你要应用到集合中每个元素的行为(这里是一个谓词)区分开了。

  • 这样一来,任何需求的变更,只需要增加相应的实现类即可。filterApples方法的行为取决于你通过ApplePredicate对象传递的代码。但是会有一个问题:类膨胀
  • 代码传递/行为
  • 在上述的实现中,我们发现,对于整个测试,唯一重要的就是test方法的实现,这个方法决定了需要怎么样进行过滤。
  • 所以在传递行为的时候,我们可以直接使用匿名内部类来传递,如下
  • 对于多个无用的代码,把匿名内部类更改为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处理。

    相关文章

    java命令行参数 java命令行参数表示形式

    命令行参数就是main方法里面的参数String[] args他就是一个数组,args只是数据类型的一个名称,就是一个数组的变量,名称无所谓,类型没变就行了。这个就是程序的入口点。如图7.4所示:图7...

    Java启动参数设置 java启动参数设置java.exe名字

    set JAVA_OPTS=-Xms4g -Xmx4g -Xmn3g -XX:SurvivorRatio=6 -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=2...

    java -server -jar 启动参数详解 java启动jar包命令

    一、使用G1 (jdk8)java -server -Xmx4G -Xms4G -XX:MaxMetaspaceSize=384M -XX:MetaspaceSize=384M -XX:+UseG1G...

    SpringBoot使用@Valid注解+Exception全局处理器优雅处理参数验证

    目录一、为什么使用 @Valid 来验证参数二、@Valid 注解的作用三、@Valid 的相关注解四、使用 @Valid 进行参数校验步骤实体类中添加 @Valid 相关注解接口类中添加 @Vali...

    SpringBoot 参数校验的方法 springboot参数校验不生效

    Introduction有参数传递的地方都少不了参数校验。在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全。试想一下,如果在controller层中没有经过任何校验的参数通过se...