Java 8を使用したポリモーフィズムのリファクタリング


8

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は初めてなので、複数のクラスを作成せずにこのコードをリファクタリングする方法はありますか?インターフェースに含まれるメソッドは1つだけなので、ラムダを使用してリファクタリングできますか?


1
春はさておき、あなたがしていることは、セットの包含チェックだけです。セットをコンストラクタパラメータとして挿入します。
アンディターナー

回答:


5

現在のデザインに固執したい場合は、次のようにすることができます。

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がアプリケーションコンテキストに存在しないため、現在は失敗します-あまり良い方法ではありません。

そのため、サポートされているプラ​​ットフォームのセットへのタイプのマップを作成し、構成でマップを維持するか、スプリングで魔法をかけることができます。あなたはこのようなものになるでしょう:

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の機能がありません;)


4

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の回答に書かれているように、これを構成に移動できます。

そのように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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.