首页 > 解决方案 > 在实例变量中存储函数(Java)

问题描述

当类中的其他方法多次使用它们时,我喜欢在私有和最终实例变量中存储可以表示为一行 lambda 的简单函数。

此外,有时我会使用未多次使用的函数来缩短大方法并更好地表达方法中使用的功能。

    public class SomeClass {
    private final UnaryOperator<Something> someMethod = s -> doSomething;

    public void someMethod2(Something s) {
        //some code which goes over several lines and uses someMethod variable
    }

    public void someMethod3(Something s) {
        //some code which goes over several lines and uses someMethod variable
    }
}

另一个示例,其中为帮助程序类中的不同服务预先准备了输入。必须在两个服务的字符串中替换两个相同的字符。这个函数没有存储一个普通的静态方法,它存储在一个实现 UnaryOperator 的静态字段中。

public class PrepareServicesInputHelper {
    private static final UnaryOperator<String> replaceSignsForAllServices = s -> s.replace('+', '-')
            .replace('/', '*');

    public static String transformStringForServiceOne(String s) {
        return "Additional transformation information for service one" + removeUnwantedSigns.apply(s);
    }

    public static String transformStringForServiceTwo(String s) {
        return "Additional transformation information for service two:" + removeUnwantedSigns.apply(s);
    }
}

它看起来更好,对我来说更清晰。

这是一个好主意,还是有一些实用的缺点,或者使用这种方法损害了一些干净代码的范例,并且功能应该传统地存储在实例方法中?

标签: java-8functional-programmingobject-oriented-analysismethod-referencefunctional-interface

解决方案


在您的示例中,与仅简单地调用方法相比,我看不到您的解决方案的任何附加价值。您的解决方案是矫枉过正。

亚伯拉罕马斯洛(https://en.wikipedia.org/wiki/Law_of_the_instrument):

我想如果你唯一的工具是一把锤子,那么把所有东西都当作钉子一样对待是很诱人的。

lambdas 的正确用例是您需要传递一个函数,或者从多个可能的函数中选择一个函数。在这里,您的用例只是对方法的简单重用,由 lambda 混淆。

研究行为设计模式herehere,例如Command、Observer/Listener、Strategy、Visitor。在这里,您需要传递一个行为,这就是 lambda 在 Java 中的设计目的。

另一个快速的“经验法则”可能是这样的:

  1. 您现在需要调用方法 ?所以调用一个方法。
  2. 您是否需要传递一个方法以从另一个方法内部调用,稍后,可能不是一次而是多次调用,甚至可能根本不需要(如果控制中的方法决定)?所以传递一个 lambda。

对于您的用例,常见的方法是这样。这样看起来更好清晰:)

public class PrepareServicesInputHelper {
    private static String replaceSignsForAllServices(final String s) {
        return s.replace('+', '-').replace('/', '*');
    }

    public static String transformStringForServiceOne(final String s) {
        return "Additional transformation information for service one" + removeUnwantedSigns(s);
    }

    public static String transformStringForServiceTwo(final String s) {
        return "Additional transformation information for service two:" + removeUnwantedSigns(s);
    }
}

一个很好的例子,与你的相似但不一样,就是这个。您有一个写入文件的记录器,但前提是您打开了日志记录。评估日志文本可能代价高昂,我们只想在需要时才懒惰地计算它。

public class Logger {
    private boolean logIsOn;
    // constructor, setters, getters etc.

    public log(final String message) {
        if (logIsOn) {
            printToFile(message);
        }
    }

    public lazyLog(final Supplier<String> message) {
        if (logIsOn) {
            printToFile(message.get());
        }
    }
}

// Here the expensive calculation occurs always, even if the logging is off
logger.log("Operation x performed on " + 
    person.getFirstName() + " " +
    person.getLastName() + 
    " with the result " + result.calculate()); 

// Here the expensive calculation occurs only when the logging is on
logger.lazyLog(() -> "Operation x performed on " + 
    person.getFirstName() + " " +
    person.getLastName() + 
    " with the result " + result.calculate()); 

推荐阅读