代码之家  ›  专栏  ›  技术社区  ›  PatPanda

java—在SpringBootWebFlux(函数式程序风格)中,委托给私有静态方法比私有方法有什么好处

  •  0
  • PatPanda  · 技术社区  · 4 年前

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

    
    @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);
    
    }
    
    

    (问题不在上面)

    现在,作为服务层的实现:首先,一个面向公众的方法将所有计算委托给后续服务层的版本 私有静态方法

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

    而不是直接在私有数据库中使用字段 但非静态

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

    (把它们放在一起)

    together

    问题:

    选项1可以带来哪些好处?

    这是一个技术性的问题,不是基于观点的。我确信不仅仅是代码样式的首选项。我看到越来越多的项目在JavaWebFlux功能程序的上下文中采用选项1。

    • 与选项2相比,选项1在运行时性能方面有哪些好处?

    • 与选项2相比,选项1在可测试性方面有哪些好处?

    • 与选项2相比,模拟选项1有哪些好处?

    • 与选项2相比,选项1在可维护性方面有哪些好处?

    • 与选项2相比,选项1在可读性方面有哪些好处?

    • 与选项2相比,选项1还有哪些其他好处?

    非常感谢。

    0 回复  |  直到 4 年前
        1
  •  1
  •   Mark Bramnik    4 年前

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

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

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

    这意味着您可能需要使用private static methods 如果:

    • 您只能在类中使用它们
    • 您需要强调的是,该方法不依赖于(读取不访问)其定义的对象的内部状态。

    相反,如果您已经维护了状态/依赖项,如 WebClient 在示例中,然后使用 static 使您可以将此参数传递给方法。在我看来,这是不必要的:如果您没有1个参数,但要传递3个参数,并且您从源类中的许多位置调用此方法,该怎么办。

    除此之外,我看不出有什么不同:

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

    • 性能损失——大致相同,我不认为使用一种方法而不是另一种方法会导致性能问题。

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

    • 多线程-如果需要,您应该同步这两种情况下的状态,即方法具有 静止的

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