【问题标题】:Storing functions in instance variables(Java)在实例变量中存储函数(Java)
【发布时间】:2019-11-03 07:21:00
【问题描述】:

当类中的其他方法多次使用它们时,我喜欢在私有和最终实例变量中存储可以表示为一行 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);
    }
}

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

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

【问题讨论】:

  • 您真的需要实例变量还是static 也可以?
  • 在这种情况下,静态变量也可以做到这一点。但是我看不到这样做的好处,如果静态变量只能由实例方法使用并且由于它是私有的而没有实例就无法访问。
  • 好处是您的实例将占用更少的内存,并且它们都将共享一个 lambda 函数对象,而不是每个实例都有自己的副本。
  • 我想看看您的真实用例,否则我无法判断您的方法是否良好,或者它是否滥用或误解了 Java 函数式方法。
  • @HonzaZidek 添加了另一个示例。

标签: java-8 functional-programming object-oriented-analysis method-reference functional-interface


【解决方案1】:

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

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

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

lambda 的正确用例是您需要传递一个函数,或者从多个可能的函数中选择一个函数。在这里,您的用例只是对方法的简单重用,由 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()); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    相关资源
    最近更新 更多