在实例变量中存储函数(Java)

Storing functions in instance variables(Java)

我喜欢存储简单的函数,当它们被其他方法在 class.

中多次使用时,可以将它们表示为私有和最终实例变量中的一行 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
    }
}

另一个示例,其中在助手中为不同的服务预先准备了输入 class。必须在两个服务的字符串中替换两个相同的字符。这个函数没有存储在普通的静态方法中,它存储在实现 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);
    }
}

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

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

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

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

I suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail.

lambda 的正确用例是您需要传递一个函数,或者 select 从多个可能的函数传递给一个函数。在这里,您的用例只是一个简单的 re-use 方法,由 lambda 混淆。

研究行为设计模式here or here,例如命令、Observer/Listener、策略、访问者。在这里你需要 传递 一个行为,这就是在 Java.

中设计的 lambda 的目的

另一个快速"rule of thumb"可能是这样的:

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

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

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());