首页 > 解决方案 > java - 委托给私有静态方法比springboot webflux中的私有方法有什么好处(函数式程序风格)

问题描述

我有一个关于在 java springboot webflux 项目的上下文中使用私有静态方法的问题。

让我先放一些代码:

一个spring项目的简单代码:一个Main类,config包下的Configuration类,包repository下的Repository类,service包下的Service接口。


@SpringBootApplication
public class SomeApplication {

    public static void main(String[] args) {
        SpringApplication.run(SomeApplication.class, args);
    }

}

@Configuration
public class SomeConfiguration {

    @Value("${someConfiguration}")
    private String someConfiguration;

    public String getSomeConfiguration() {
        return someConfiguration;
    }

}

@Repository
public interface SomeRepository extends Reactive[...]Repository<String, String> { }

public interface SomeService {

    Mono<String> someCompute(String string);

}

(问题不在上面)

现在,作为服务层的实现:首先,面向公众的方法将所有计算委托给后续私有静态方法的版本,将字段作为参数传递。(选项1)

@Service
public class SomeServiceImpl implements SomeService {

    private final SomeConfiguration someConfiguration;
    private final SomeRepository    someRepository;
    private final WebClient         webClient;

    @Autowired
    public SomeServiceImpl(SomeConfiguration someConfiguration, SomeRepository someRepository, WebClient webClient) {
        this.someConfiguration = someConfiguration;
        this.someRepository = someRepository;
        this.webClient = webClient;
    }

    @Override
    public Mono<String> someCompute(String string) {
        Mono<String> s1Mono = sendHttpRequestToSomewhere(webClient);
        Mono<String> s2Mono = s1Mono.map(x -> computeSomethingWithConfiguration(x, someConfiguration));
        Mono<Object> s3Mono = s2Mono.map(x -> saveToSomewhere(x, someRepository));
        return s3Mono.map(x -> computeSomethingElse(x));
    }

    private static Mono<String> sendHttpRequestToSomewhere(WebClient webClient) {
        return webClient.get().retrieve().bodyToMono(String.class);
    }

    private static String computeSomethingWithConfiguration(String x, SomeConfiguration someConfiguration) {
        return x + someConfiguration.getSomeConfiguration();
    }

    private static Mono<String> saveToSomewhere(String x, SomeRepository someRepository) {
        return someRepository.save(x);
    }

    private static String computeSomethingElse(Object x) {
        return x.toString();
    }

}

与在私有但非静态方法中直接使用字段相反。(选项 2)

@Service
public class SomeServiceImpl implements SomeService {

    private final SomeConfiguration someConfiguration;
    private final SomeRepository    someRepository;
    private final WebClient         webClient;

    @Autowired
    public SomeServiceImpl(SomeConfiguration someConfiguration, SomeRepository someRepository, WebClient webClient) {
        this.someConfiguration = someConfiguration;
        this.someRepository = someRepository;
        this.webClient = webClient;
    }

    @Override
    public Mono<String> someCompute(String string) {
        Mono<String> s1Mono = sendHttpRequestToSomewhere();
        Mono<String> s2Mono = s1Mono.map(x -> computeSomethingWithConfiguration(x));
        Mono<Object> s3Mono = s2Mono.map(x -> saveToSomewhere(x));
        return s3Mono.map(x -> computeSomethingElse(x));
    }

    private Mono<String> sendHttpRequestToSomewhere() {
        return webClient.get().retrieve().bodyToMono(String.class);
    }

    private String computeSomethingWithConfiguration(String x) {
        return x + someConfiguration.getSomeConfiguration();
    }

    private Mono<String> saveToSomewhere(String x) {
        return someRepository.save(x);
    }

    private String computeSomethingElse(Object x) {
        return x.toString();
    }

}

(把它们放在一起)

一起

问题:

选项1可以带来什么好处?

这是一个技术问题,不是基于意见的。我相信不仅仅是代码风格偏好。我看到越来越多的项目在 java webflux 功能程序的上下文中采用选项 1。

谢谢

标签: javaspringspring-bootspring-webflux

解决方案


我认为这个问题通常与 WebFlux 和 Spring 无关,而是与任何以函数式样式编写的代码有关(Java 8 流也会遇到同样的问题),甚至与以“传统”编写的代码有关命令式风格:什么叫私有静态或私有方法?

一般来说,我只能看到私有静态方法和私有方法之间的一个区别:

私有非静态方法可以访问类的状态/依赖项(非静态数据字段),而私有静态方法不能

这意味着您可能希望在以下情况下使用私有static methods

  • 你只在课堂上使用它们
  • 您想强调该方法不依赖(读取不访问)其定义的对象的内部状态。

相反,如果您已经维护了状态/依赖关系,就像WebClient在示例中一样,那么使用static会使您将此参数传递给方法。在我看来,这是不必要的:如果您没有 1 个,而是说 3 个要传递的参数,并且您从源类中的许多地方调用此方法,该怎么办。

除此之外,我没有看到太大的区别:

  • 模拟(测试)是一样的,因为无论如何您都不测试私有方法,并且您可以通过使用构造函数注入或一些高级模拟技术以相同的方式模拟两种情况下的依赖关系。

  • 性能损失 - 大致相同,我无法考虑使用一种方法而不是另一种方法会导致性能问题的情况。

  • 可维护性——同样,取决于你的用例,如果方法正在访问内部状态,你最好使用非静态变体来减少混乱,如果你想强调你使用不依赖于状态的“util”方法——使用private static方法。

  • 多线程 - 如果需要,您应该在两种情况下同步状态,该方法本身具有修饰符这一事实static根本不处理多线程。

我还发现这个线程对这个问题很有用,它同样适用于一般编程风格(代码组织),不仅适用于 webflux。


推荐阅读