构建灵活的函数:使用 Builder 模式处理函数或浮点数参数

构建灵活的函数:使用 Builder 模式处理函数或浮点数参数

使用 Builder 模式处理函数或浮点数参数

在编写需要灵活配置参数的函数时,我们经常会遇到这样的需求:某些参数既可以接受一个具体的数值,也可以接受一个函数,该函数根据输入动态地计算出数值。如果直接使用方法重载,会导致大量的重复代码,难以维护。本文将介绍如何使用 Builder 模式来解决这个问题,提供一种更优雅、更灵活的解决方案。

Builder 模式简介

Builder 模式是一种创建型设计模式,它将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。简单来说,Builder 模式允许我们一步一步地构建一个对象,而不是一次性地将所有参数传递给构造函数。这在参数数量较多,且部分参数可选的情况下非常有用。

实现 RangeBuilder

假设我们需要创建一个 RangeBuilder 类,用于生成一个函数,该函数接受一个 PVector 对象作为输入,并返回一个 double 值。该函数的核心逻辑是根据输入的 PVector 对象,结合 scale、min 和 max 三个参数,计算出一个映射后的值。这三个参数都可以是 Double 类型的数值,也可以是一个 function 函数。

下面是 RangeBuilder 类的代码实现:

import java.util.List; import java.util.function.Function; import java.util.stream.Stream; import java.io.IOException;  class PVector {     public double x;     public double y;      public PVector(double x, double y) {         this.x = x;         this.y = y;     } }  public class RangeBuilder {      private Function<PVector, Double> scale;     private Function<PVector, Double> min;     private Function<PVector, Double> max;      public RangeBuilder scale(Function<PVector, Double> scale) {         this.scale = scale;         return this;     }      public RangeBuilder scale(double scale) {         return scale(in -> scale);     }      public RangeBuilder min(Function<PVector, Double> min) {         this.min = min;         return this;     }      public RangeBuilder min(double min) {         return min(in -> min);     }      public RangeBuilder max(Function<PVector, Double> max) {         this.max = max;         return this;     }      public RangeBuilder max(double scale) {         return max(in -> scale);     }      public Function<PVector, Double> build() {         return pv -> map(noise(pv.x * scale.apply(pv), pv.y * scale.apply(pv)), 0, 1, min.apply(pv), max.apply(pv));     }      // Mock noise and map functions for demonstration     private double noise(double x, double y) {         // Replace with your actual noise function implementation         return (Math.sin(x) + Math.cos(y)) / 2.0; // Example noise function     }      private double map(double value, double start1, double stop1, double start2, double stop2) {         return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));     }      public static void main(String... args) throws IOException {         List<PVector> pvs = List.of(new PVector(0, 0));          Stream<Double> s = pvs.stream().map(new RangeBuilder().scale(.02)                 .min(0)                 .max(255)                 .build());         Stream<Double> s2 = pvs.stream().map(new RangeBuilder().scale(new RangeBuilder().scale(.02)                 .min(.1)                 .max(.002)                 .build())                 .min(0)                 .max(255)                 .build());          s.forEach(System.out::println);         s2.forEach(System.out::println);      }  }

代码解释:

  1. 成员变量 scale、min 和 max 都是 Function 类型的成员变量,用于存储对应的函数。
  2. Builder 方法: scale(Function scale)、min(Function min) 和 max(Function max) 方法用于设置对应的函数。这些方法都返回 RangeBuilder 实例本身,以便链式调用。
  3. 重载方法: scale(double scale)、min(double min) 和 max(double scale) 方法是重载方法,用于直接设置数值。这些方法内部调用了对应的函数设置方法,并将数值包装成一个简单的 Lambda 表达式 in -> scale,从而将数值转换为函数。
  4. build() 方法: build() 方法用于构建最终的函数。该方法返回一个 Function 对象,该对象内部使用了 scale、min 和 max 三个函数来计算最终的映射值。
  5. main() 方法: main() 方法展示了如何使用 RangeBuilder 类来构建用于 Stream 的函数。通过链式调用 scale()、min() 和 max() 方法,可以灵活地配置参数。

使用示例

以下代码展示了如何使用 RangeBuilder 类来构建函数,并将其应用于 Stream:

List<PVector> pvs = List.of(new PVector(0, 0));  Stream<Double> s = pvs.stream().map(new RangeBuilder().scale(.02)                                                       .min(0)                                                       .max(255)                                                       .build()); Stream<Double> s2 = pvs.stream().map(new RangeBuilder().scale(new RangeBuilder().scale(.02)                                                                                 .min(.1)                                                                                 .max(.002)                                                                                 .build())                                                        .min(0)                                                        .max(255)                                                        .build());

在这个例子中,s 和 s2 都是 Stream 类型的 Stream。s 使用了固定的数值作为 scale、min 和 max 参数,而 s2 使用了一个嵌套的 RangeBuilder 来生成 scale 参数。

总结

使用 Builder 模式可以有效地解决函数参数既可以是数值,也可以是函数的问题。通过将数值包装成 Lambda 表达式,可以统一参数类型,避免代码重复。Builder 模式还提供了更灵活的 API 设计,使得我们可以一步一步地配置参数,从而提高代码的可读性和可维护性。在实际应用中,可以根据具体的需求,灵活地调整 Builder 类的实现方式,以满足不同的场景。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享