动态地从父类转换为合适的子类在一个方法中。

huangapple go评论94阅读模式
英文:

Dynamically cast to a proper subclass from parent class in a method

问题

我有一个Java interface 叫做 PlatformConfigurable。我还有两个类 PlatformProducerConfigPlatformConsumerConfig

后来,我需要为这两个类添加一个共同的配置,将一个属性设置为空字符串:

  1. private PlatformConfigurable disableHostNameVerificationConfig(PlatformConfigurable platformConfig) {
  2. if (platformConfig instanceof PlatformProducerConfig) {
  3. PlatformProducerConfig oldConfig = (PlatformProducerConfig) platformConfig;
  4. Map<String, String> additionalConfig = oldConfig.additionalProperties();
  5. Map<String, String> newConfig = new HashMap<>(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  6. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  7. return oldConfig.toBuilder().additionalProperties(newConfig).build();
  8. }
  9. else if (platformConfig instanceof PlatformConsumerConfig) {
  10. PlatformConsumerConfig oldConfig = (PlatformConsumerConfig) platformConfig;
  11. Map<String, String> additionalConfig = platformConfig.additionalProperties();
  12. Map<String, String> newConfig = new HashMap<>(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  13. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  14. return oldConfig.toBuilder().additionalProperties(newConfig).build();
  15. }
  16. return platformConfig;
  17. }

我进行了对生产者或消费者配置的强制类型转换,因为 PlatformConfigurable 接口中没有声明 .toBuilder().build() 方法,而且我无法访问修改该接口,我只能实现它。

我希望摆脱重复的代码:

  1. Map<String, String> additionalConfig = platformConfig.additionalProperties();
  2. Map<String, String> newConfig = new HashMap<>(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  3. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  4. return oldConfig.toBuilder().additionalProperties(newConfig).build();

我在考虑使用Lambda表达式,但我不确定如何做到这一点。

英文:

I have a Java interface PlatformConfigurable. I also have two classes PlatformProducerConfig and PlatformConsumerConfig.

Later on, I need to add a common config to both that sets a property to an empty string:

  1. private PlatformConfigurable disableHostNameVerificationConfig(PlatformConfigurable platformConfig) {
  2. if (platformConfig instanceof PlatformProducerConfig) {
  3. PlatformProducerConfig oldConfig = (PlatformProducerConfig) platformConfig;
  4. Map&lt;String, String&gt; additionalConfig = oldConfig.additionalProperties();
  5. Map&lt;String, String&gt; newConfig = new HashMap&lt;&gt;(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  6. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  7. return oldConfig.toBuilder().additionalProperties(newConfig).build();
  8. }
  9. else if (platformConfig instanceof PlatformConsumerConfig) {
  10. PlatformConsumerConfig oldConfig = (PlatformConsumerConfig) platformConfig;
  11. Map&lt;String, String&gt; additionalConfig = platformConfig.additionalProperties();
  12. Map&lt;String, String&gt; newConfig = new HashMap&lt;&gt;(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  13. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  14. return oldConfig.toBuilder().additionalProperties(newConfig).build();
  15. }
  16. return platformConfig;
  17. }

I am casting to producer or consumer config because the PlatformConfigurable interface doesn't have .toBuilder() or .build() methods declared in it, and I don't have access to modify the interface, as I can only implement it.

I would want to get rid of the duplicate code:

  1. Map&lt;String, String&gt; additionalConfig = platformConfig.additionalProperties();
  2. Map&lt;String, String&gt; newConfig = new HashMap&lt;&gt;(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  3. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  4. return oldConfig.toBuilder().additionalProperties(newConfig).build();

I was thinking of using lambdas, but I am not 100% sure how to do it.

答案1

得分: 5

你可以像这样重构现有的代码:

  1. private PlatformConfigurable disableHostNameVerificationConfig(PlatformConfigurable platformConfig) {
  2. if (!(platformConfig instanceof PlatformProducerConfig) && !(platformConfig instanceof PlatformConsumerConfig)) {
  3. return platformConfig;
  4. }
  5. Map<String, String> additionalConfig = platformConfig.additionalProperties();
  6. Map<String, String> newConfig = new HashMap<>(Optional.ofNullable(additionalConfig).orElseGet(Collections::emptyMap));
  7. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  8. if (platformConfig instanceof PlatformProducerConfig) {
  9. return ((PlatformProducerConfig) platformConfig).toBuilder().additionalProperties(newConfig).build();
  10. }
  11. return ((PlatformConsumerConfig) platformConfig).toBuilder().additionalProperties(newConfig).build();
  12. }

更新

另一种方法是将与构建器相关的功能提取到单独的接口中,并在代码中使用它们:

  1. // 1. 扩展现有的 `PlatformConfigurable`
  2. public interface BuilderedPlatformConfigurable extends PlatformConfigurable {
  3. ConfigPlatformBuilder toBuilder();
  4. }
  5. // 2. 提供具有共同实现的构建器接口
  6. public interface ConfigPlatformBuilder {
  7. Map<String, String> additionalProperties = new HashMap<>();
  8. BuilderedPlatformConfigurable build();
  9. default ConfigPlatformBuilder additionalProperties(Map<String, String> properties) {
  10. this.additionalProperties.clear();
  11. this.additionalProperties.putAll(properties);
  12. return this;
  13. }
  14. }
  15. // 3. 更新 PlatformConsumerConfig 类(类似地,更新 PlatformProducerConfig)
  16. public class PlatformConsumerConfig implements BuilderedPlatformConfigurable {
  17. private Map<String, String> additionalProperties = new HashMap<>();
  18. @Override
  19. public Map<String, String> additionalProperties() {
  20. return additionalProperties;
  21. }
  22. public ConfigPlatformBuilder toBuilder() {
  23. return new Builder();
  24. }
  25. public static class Builder implements ConfigPlatformBuilder {
  26. public PlatformConsumerConfig build() {
  27. PlatformConsumerConfig config = new PlatformConsumerConfig();
  28. config.additionalProperties.putAll(this.additionalProperties);
  29. return config;
  30. }
  31. }
  32. }
  33. // 4. 提供重载的方法
  34. private PlatformConfigurable disableHostNameVerificationConfig(PlatformConfigurable platformConfig) {
  35. return platformConfig;
  36. }
  37. private PlatformConfigurable disableHostNameVerificationConfig(BuilderedPlatformConfigurable platformConfig) {
  38. Map<String, String> additionalConfig = platformConfig.additionalProperties();
  39. Map<String, String> newConfig = new HashMap<>(Optional.ofNullable(additionalConfig).orElseGet(Collections::emptyMap));
  40. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  41. return platformConfig.toBuilder().additionalProperties(newConfig).build();
  42. }

注意:这只是您提供的代码的翻译部分,没有其他附加内容。

英文:

You could just refactor existing code like this:

  1. private PlatfromConfigurable disableHostNameVerificationConfig(Platfromonfigurable platfromConfig) {
  2. if (!(platformConfig instanceof PlatformProducerConfig) &amp;&amp; !(platformConfig instanceof PlatformConsumerConfig)) {
  3. return platformConfig;
  4. }
  5. Map&lt;String, String&gt; additionalConfig = platformConfig.additionalProperties();
  6. Map&lt;String, String&gt; newConfig = new HashMap&lt;&gt;(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  7. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  8. if (platformConfig instanceof PlatformProducerConfig) {
  9. return ((PlatformProducerConfig)platformConfig).toBuilder().additionalProperties(newConfig).build();
  10. }
  11. return ((PlatformConsumerConfig)platformConfig).toBuilder().additionalProperties(newConfig).build();
  12. }

Update

Another approach could be to extract functionality related to the builder to separate interfaces and use them in this way:

  1. // 1. extend existing `PlatformConfigurable`
  2. public interface BuilderedPlatformConfigurable extends PlatformConfigurable {
  3. ConfigPlatformBuilder toBuilder();
  4. }
  5. // 2. provide builder interface with common implementation
  6. public interface ConfigPlatformBuilder {
  7. Map&lt;String, String&gt; additionalProperties = new HashMap&lt;&gt;();
  8. BuilderedPlatformConfigurable build();
  9. default ConfigPlatformBuilder additionalProperties(Map&lt;String, String&gt; properties) {
  10. this.additionalProperties.clear();
  11. this.additionalProperties.putAll(properties);
  12. return this;
  13. }
  14. }
  15. // 3. update PlatformConsumerConfig class (similarly, PlatformProducerConfig)
  16. public class PlatformConsumerConfig implements BuilderedPlatformConfigurable {
  17. private Map&lt;String, String&gt; additionalProperties = new HashMap&lt;&gt;();
  18. @Override
  19. public Map&lt;String, String&gt; additionalProperties() {
  20. return additionalProperties;
  21. }
  22. public ConfigPlatformBuilder toBuilder() {
  23. return new Builder();
  24. }
  25. public static class Builder implements ConfigPlatformBuilder {
  26. public PlatformConsumerConfig build() {
  27. PlatformConsumerConfig config = new PlatformConsumerConfig();
  28. config.additionalPropertie.putAll(this.additionalProperties);
  29. return config;
  30. }
  31. }
  32. }
  33. // 4. provide overloaded method
  34. private PlatformConfigurable disableHostNameVerificationConfig(PlatformConfigurable platformConfig) {
  35. return platformConfig;
  36. }
  37. private PlatformConfigurable disableHostNameVerificationConfig(BuilderedPlatformConfigurable platformConfig) {
  38. Map&lt;String, String&gt; additionalConfig = platformConfig.additionalProperties();
  39. Map&lt;String, String&gt; newConfig = new HashMap&lt;&gt;(Optional.ofNullable(additionalConfig).orElseGet(Map::of));
  40. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  41. return platformConfig.toBuilder().additionalProperties(newConfig).build();
  42. }

答案2

得分: 4

使用泛型,对 Alex Rudenko 的答案 进行进一步扩展:

  1. private <P extends PlatformConfigurable> P disableHostNameVerificationConfig(P platformConfig, BiFunction<P, Map<String, String>, P> appender) {
  2. Map<String, String> additionalConfig = platformConfig.additionalProperties();
  3. Map<String, String> newConfig = new HashMap<>(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  4. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  5. return appender.apply(platformConfig, newConfig);
  6. }

假设对于任何 PlatformConfigurable 的子类型(包括 PlatformConfigurable 本身),这样做是安全的。

然后可以这样调用:

  1. disableHostNameVerificationConfig(
  2. platformProducerConfig,
  3. (p, config) -> p.toBuilder().setAdditionalConfig(config).build());
  4. disableHostNameVerificationConfig(
  5. platformConsumerConfig,
  6. (p, config) -> p.toBuilder().setAdditionalConfig(config).build());

如果愿意,可以创建辅助方法来隐藏 BiFunction

  1. private PlatformProducerConfig disableHostNameVerificationConfig(PlatformProducerConfig config) {
  2. return disableHostNameVerificationConfig(
  3. platformConfigurable,
  4. (p, config) -> p.toBuilder().setAdditionalConfig(config).build());
  5. }
  6. private PlatformConsumerConfig disableHostNameVerificationConfig(PlatformConsumerConfig config) {
  7. return disableHostNameVerificationConfig(
  8. platformConfigurable,
  9. (p, config) -> p.toBuilder().setAdditionalConfig(config).build());
  10. }

实际上,我认为更好的方法是不使用泛型或 lambda 表达式:编写一个方法来创建更新后的映射:

  1. private static Map<String, String> newConfig(PlatformConfigurable platformConfig) {
  2. Map<String, String> additionalConfig = platformConfig.additionalProperties();
  3. Map<String, String> newConfig = additionalConfig != null ? new HashMap<>(additionalConfig) : new HashMap<>();
  4. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  5. return newConfig;
  6. }

然后只需编写两个重载方法:

  1. private PlatformProducerConfig disableHostNameVerificationConfig(PlatformProducerConfig config) {
  2. return config.toBuilder().setAdditionalConfig(newConfig(config)).build();
  3. }
  4. private PlatformConsumerConfig disableHostNameVerificationConfig(PlatformConsumerConfig config) {
  5. return config.toBuilder().setAdditionalConfig(newConfig(config)).build();
  6. }
英文:

Taking Alex Rudenko's answer a bit further, using generics:

  1. private &lt;P extends PlatformConfigurable&gt; P disableHostNameVerificationConfig(P platformConfig, BiFunction&lt;P, Map&lt;String, String&gt;, P&gt; appender) {
  2. Map&lt;String, String&gt; additionalConfig = platformConfig.additionalProperties();
  3. Map&lt;String, String&gt; newConfig = new HashMap&lt;&gt;(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  4. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  5. return appender.apply(platformConfig, newConfig);
  6. }

This assumes that it is safe to do this for any subtype of PlatformConfigurable (and PlatformConfigurable itself).

Then invoke like:

  1. disableHostNameVerificationConfig(
  2. platformProducerConfig,
  3. (p, config) -&gt; p.toBuilder().setAdditionalConfig(config).build());
  4. disableHostNameVerificationConfig(
  5. platformConsumerConfig,
  6. (p, config) -&gt; p.toBuilder().setAdditionalConfig(config).build());

If you like, create helper methods to hide the BiFunctions:

  1. private PlatformProducerConfig disableHostNameVerificationConfig(PlatformProducerConfig config) {
  2. return disableHostNameVerificationConfig(
  3. platformConfigurable,
  4. (p, config) -&gt; p.toBuilder().setAdditionalConfig(config).build());
  5. }
  6. private PlatformConsumerConfig disableHostNameVerificationConfig(PlatformConsumerConfig config) {
  7. return disableHostNameVerificationConfig(
  8. platformConfigurable,
  9. (p, config) -&gt; p.toBuilder().setAdditionalConfig(config).build());
  10. }

Actually, I think a better way to do it would be without generics or lambdas: write a method which creates an updated map:

  1. private static Map&lt;String, String&gt; newConfig(PlatformConfigurable platformConfig) {
  2. Map&lt;String, String&gt; additionalConfig = platformConfig.additionalProperties();
  3. Map&lt;String, String&gt; newConfig = additionalConfig != null ? new HashMap&lt;&gt;(additionalConfig) : new HashMap&lt;&gt;();
  4. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  5. return newConfig;
  6. }

and then just have two overloads:

  1. private PlatformProducerConfig disableHostNameVerificationConfig(PlatformProducerConfig config) {
  2. return config.toBuilder().setAdditionalConfig(newConfig(config)).build();
  3. }
  4. private PlatformConsumerConfig disableHostNameVerificationConfig(PlatformConsumerConfig config) {
  5. return config.toBuilder().setAdditionalConfig(newConfig(config)).build();
  6. }

答案3

得分: 1

  1. // 添加在Alex Rudenko的回答中的一点,并创建不同函数以添加不同接口的实现。
  2. private PlatformConfigurable disableHostNameVerificationConfig(PlatformConfigurable platformConfig) {
  3. if ((platformConfig == null)) {
  4. return platformConfig;
  5. }
  6. Map<String, String> additionalConfig = platformConfig.additionalProperties();
  7. Map<String, String> newConfig = new HashMap<>(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  8. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, "");
  9. return PlatformConfigurableObject(platformConfig, newConfig);
  10. }
  11. // 因此,您可以在不同的方法中处理所有实例,以后只需更改此方法即可添加后续的PlatformXCofing类。单一责任原则。
  12. private PlatformConfigurable PlatformConfigurableObject(PlatformConfigurable platformConfig, Map<String, String> newConfig) {
  13. if (platformConfig instanceof PlatformProducerConfig) {
  14. return ((PlatformProducerConfig) platformConfig).toBuilder().additionalProperties(newConfig).build();
  15. } else if (platformConfig instanceof PlatformConsumerConfig) {
  16. return ((PlatformConsumerConfig) platformConfig).toBuilder().additionalProperties(newConfig).build();
  17. } else {
  18. return platformConfig;
  19. }
  20. }
英文:

Adding one thing in Alex Rudenko's answer, and making different function to add different implementations of interfaces.

  1. private PlatformConfigurable disableHostNameVerificationConfig(PlatformConfigurable platformConfig) {
  2. if ((platformConfig == null)) {
  3. return platformConfig;
  4. }
  5. Map&lt;String, String&gt; additionalConfig = platformConfig.additionalProperties();
  6. Map&lt;String, String&gt; newConfig = new HashMap&lt;&gt;(Optional.ofNullable(additionalConfig).orElseGet(ImmutableMap::of));
  7. newConfig.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, &quot;&quot;);
  8. return PlatformConfigurableObject(platformConfig, newConfig);
  9. }

So you can handle all instances in a different method, and whenever PlatfromXCofing classes are added later you only have to change this method. Single Responsibility Principle.

  1. private PlatformConfigurable PlatformConfigurableObject(PlatformConfigurable platformConfig, Map&lt;String, String&gt; newConfig){
  2. if (platformConfig instanceof PlatformProducerConfig) {
  3. return ((PlatformProducerConfig)platformConfig).toBuilder().additionalProperties(newConfig).build();
  4. } else if (platformConfig instanceof PlatformConsumerConfig){
  5. return ((PlatformConsumerConfig)platformConfig).toBuilder().additionalProperties(newConfig).build();
  6. } else{
  7. return platformConfig;
  8. }
  9. }

huangapple
  • 本文由 发表于 2020年5月29日 23:57:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/62089984.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定