【问题标题】:Refactor polymorphism using Java 8使用 Java 8 重构多态性
【发布时间】:2020-01-21 06:59:07
【问题描述】:

我有一个旧代码库,需要使用 Java 8 重构,所以我有一个接口,它告诉我当前站点是否支持该平台。

public interface PlatformSupportHandler {   
  public abstract boolean isPaltformSupported(String platform);
}

我有多个实现它的类,每个类支持不同的平台。

一些实现类是:

@Component("bsafePlatformSupportHandler")
public class BsafePlatoformSupportHandler implements PlatformSupportHandler {

  String[] supportedPlatform = {"iPad", "Android", "iPhone"};
  Set<String> supportedPlatformSet = new HashSet<>(Arrays.asList(supportedPlatform)); 

  @Override
  public boolean isPaltformSupported(String platform) {

    return supportedPlatformSet.contains(platform);
  }

}

另一种实现:

@Component("discountPlatformSupportHandler")
public class DiscountPlatoformSupportHandler implements PlatformSupportHandler{

  String[] supportedPlatform = {"Android", "iPhone"};
  Set<String> supportedPlatformSet = new HashSet<>(Arrays.asList(supportedPlatform)); 

  @Override
  public boolean isPaltformSupported(String platform) {

  return supportedPlatformSet.contains(platform);
  }
}

在我的过滤器运行时,我得到了我想要的所需 bean:

platformSupportHandler = (PlatformSupportHandler) ApplicationContextUtil
  .getBean(subProductType + Constants.PLATFORM_SUPPORT_HANDLER_APPEND);

并致电isPlatformSupported 了解我当前的站点是否支持以下平台。

我是 Java 8 的新手,有什么方法可以在不创建多个类的情况下重构此代码?由于接口只包含一个方法,我能不能用 lambda 来重构它?

【问题讨论】:

  • 抛开春天,当然:你所做的只是对集合进行包含检查。将集合作为构造函数参数注入。

标签: java spring java-8


【解决方案1】:

如果你想坚持当前的设计,你可以这样做:

public class MyGeneralPurposeSupportHandler implements PlatformSupportHandler {
   private final Set<String> supportedPlatforms;
   public MyGeneralPurposeSupportHandler(Set<String> supportedPlatforms) {
      this.supportedPlatforms = supportedPlatforms;
   } 

   public boolean isPlatformSupported(String platform) {
     return supportedPlatforms.contains(platform);
   }
}

// now in configuration:

@Configuration
class MySpringConfig {

    @Bean
    @Qualifier("discountPlatformSupportHandler") 
    public PlatformSupportHandler discountPlatformSupportHandler() {
       return new MyGeneralPurposeSupportHandler(new HashSefOf({"Android", "iPhone"})); // yeah its not a java syntax, but you get the idea
    }

    @Bean
    @Qualifier("bsafePlatformSupportHandler") 
    public PlatformSupportHandler bsafePlatformSupportHandler() {
       return new MyGeneralPurposeSupportHandler(new HashSefOf({"Android", "iPhone", "iPad"}));
    }   

}

此方法的优点是不为每种类型(折扣、bsafe 等)创建类,因此这回答了问题。

更进一步,如果没有请求类型会发生什么,目前它将失败,因为 bean 不存在于应用程序上下文中 - 这不是一个真正好的方法。

因此,您可以创建一个类型映射到一组受支持的平台,在配置中维护映射或让 spring 发挥它的魔力。 你最终会得到这样的结果:

public class SupportHandler {

   private final Map<String, Set<String>> platformTypeToSuportedPlatforms;

   public SupportHandler(Map<String, Set<String>> map) {
       this.platformTypeToSupportedPlatforms = map; 
   }

   public boolean isPaltformSupported(String type) {
        Set<String> supportedPlatforms = platformTypeToSupportedPlatforms.get(type);
        if(supportedPlatforms == null) {
          return false; // or maybe throw an exception, the point is that you don't deal with spring here which is good since spring shouldn't interfere with your business code
        }
        return supportedPlatforms.contains(type);

   }
}

@Configuration 
public class MyConfiguration {

    // Configuration conf is supposed to be your own way to read configurations in the project - so you'll have to implement it somehow
    @Bean
    public SupportHandler supportHandler(Configuration conf) {
      return new SupportHandler(conf.getRequiredMap());
    }
}

现在,如果您采用这种方法,添加新的受支持类型就完全没有代码了,您只需添加一个配置,这是迄今为止我能提供的最佳方法。

不过,这两种方法都缺少 java 8 的特性;)

【讨论】:

    【解决方案2】:

    您可以在可以创建 bean 的配置类中使用以下内容:

    @Configuration 
    public class AppConfiguration {
    
        @Bean(name = "discountPlatformSupportHandler")
        public PlatformSupportHandler discountPlatformSupportHandler() {
            String[] supportedPlatforms = {"Android", "iPhone"};
            return getPlatformSupportHandler(supportedPlatforms);
        }
    
        @Bean(name = "bsafePlatformSupportHandler")
        public PlatformSupportHandler bsafePlatformSupportHandler() {
            String[] supportedPlatforms = {"iPad", "Android", "iPhone"};
            return getPlatformSupportHandler(supportedPlatforms);
        }
    
        private PlatformSupportHandler getPlatformSupportHandler(String[] supportedPlatforms) {
            return platform -> Arrays.asList(supportedPlatforms).contains(platform);
        }
    }
    

    另外,当你想使用 bean 时,也很简单:

    @Component
    class PlatformSupport {
    
        // map of bean name vs bean, automatically created by Spring for you
        private final Map<String, PlatformSupportHandler> platformSupportHandlers;
    
        @Autowired // Constructor injection
        public PlatformSupport(Map<String, PlatformSupportHandler> platformSupportHandlers) {
            this.platformSupportHandlers = platformSupportHandlers;
        }
    
        public void method1(String subProductType) {
            PlatformSupportHandler platformSupportHandler = platformSupportHandlers.get(subProductType + Constants.PLATFORM_SUPPORT_HANDLER_APPEND);
        }
    }
    

    【讨论】:

      【解决方案3】:

      正如Mark Bramnik's 回答中所写,您可以将其移至配置。

      假设它会以这种方式在 yaml 中:

      platforms:
          bsafePlatformSupportHandler: ["iPad", "Android", "iPhone"]
          discountPlatformSupportHandler: ["Android", "iPhone"]
      

      然后你可以创建配置类来阅读这个:

      @Configuration
      @EnableConfigurationProperties
      @ConfigurationProperties
      public class Config {
      
          private Map<String, List<String>> platforms = new HashMap<String, List<String>>();
      
          // getters and setters
      

      您可以创建带有检查代码的处理程序。 或者将其放在您的过滤器中,如下所示:

      @Autowired
      private Config config;
      
      ...
      
      public boolean isPlatformSupported(String subProductType, String platform) {
          String key = subProductType + Constants.PLATFORM_SUPPORT_HANDLER_APPEND;
          return config.getPlatforms()
              .getOrDefault(key, Collections.emptyList())
              .contains(platform);
      }
      

      【讨论】:

        猜你喜欢
        • 2021-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-29
        • 2012-12-15
        • 1970-01-01
        • 2016-07-12
        • 1970-01-01
        相关资源
        最近更新 更多