如何将DRY原则应用于Java中的函数?



在JSF应用程序中,我有一些具有多个返回点的方法,如下所示:

public String Method1() {
...
if (condition1) {
elaborate1();
return "Case1";
}
if (condition2) {
elaborate2();
return "Case2";
}
if (condition3) {
elaborate3();
return "Case3";
}
...
}

这些条件和随后的阐述对于更多的方法来说是共同的,我只想写一次。不幸的是,由于有多个返回点,重构并不容易。

我对功能接口不太满意,但是我希望我可以用它们来重构上面的代码。我的想法是这样写:

String elaboration1 ( T NextElaborations) {
if (condition1) {
elaborate1();
return "Case1";
}
return NextElaborations.get();
}

有可能吗?我卡住了,网上的大多数例子都使用lambdas而不是方法。

更新1@Alexander Ivanchenko在评估你的答案之前,我需要研究你提供的链接,我不熟悉流。

在发布了这个问题之后,我用函数式接口做了一些练习,最终得到了以下伪java代码:

@FunctionalInterface
public interface MethodComposition {
String Execute(Supplier<String> supplier)
}
...
String FinalStep() {
FinalElaboration();
return "finalResult";
}
String ElaborationX(Supplier<String> supplier) {
if (conditionX) {
elaborationX();
return "ResultX";
}
return supplier.get();
}
...

public String Method1() {
Supplier<String> finalSupplier = this::FinalStep;
MethodComposition stepX = this::ElaborationX;
...
return step1.Execute(() -> 
step2.Execute(() ->
...
stepN.Execute(finalSupplier))); 
}

尽管语法丑陋,但它非常接近我想要的,我需要更多的灵活性,因为detailationx ()Method1中非常相似但不相等和Method_N.

你可以定义一个集合函数表示这些条件并通过提供方便的与类交互的方式将此集合封装在类中。这将使这个逻辑可重用。

例如,您可以创建一个映射来关联一个Predicate,它是一个函数,表示一个解析为boolean值的条件,并具有一个特定的返回。集合应该有一个可预测的迭代顺序,以确保条件将被应用的顺序,因此你可以使用LinkedHashMap来强制迭代的顺序。

您可以通过将单独的条件表示为包含谓词和一些附加属性的对象来实现更大的灵活性。这将允许对条件进行分类并构造不同的谓词组合。

您的方法Method1()if语句链可以替换为映射条目流。或者,如果您使用流填充不舒服,则可以使用普通的for循环来代替它。关键是您需要一个平均值来对函数集合执行迭代。

我对功能界面不太熟悉,但是…

我卡住了,网上的大多数例子都使用lambdas而不是方法。

不需要生成许多像elaboration1(),elaboration2()等相互依赖的方法,这种方法是不灵活的。这种方法与Java中的函数式接口(您已经提到过)和一般的函数式方法编程无关。如果你想重构你的代码,使其具有函数式风格,那么除了熟悉函数式编程,没有其他的方法了。

我建议您看看这些关于lambda表达式和的官方教程

流逻辑描述:

  • 确定具有匹配谓词true的条目
  • 通过应用findFirst()操作,将此条目作为Optional类型的对象(如果没有找到结果则为空)来终止流管道。
  • 转换可选的内容并返回结果值(可选有很多处理方法,更多信息请查看本页)

实现可能是这样的:

public class FunctionStorage {

public static final Map<Predicate<String>, String> conditions = new LinkedHashMap<>(); // LinkedHashMap insures the order of iteration

static {
conditions.put(s -> false, "1");
conditions.put(s -> true,  "2");
conditions.put(s -> false, "3");
}

public static Stream<Map.Entry<Predicate<String>, String>> getConditions() {
return conditions.entrySet().stream();
}  
}

main()

public static void main(String[] args) {
String result = FunctionStorage.getConditions()        // a stream of entries
.filter(entry -> entry.getKey().test("someValue")) // filtering the entry containing the matching condition
.findFirst()
.map(Map.Entry::getValue)                          // extracting the return value
.orElse("defaultValue"); // orElseThrow() depending on your needs
}

最新更新