Đa hình tái cấu trúc sử dụng Java 8


8

Tôi có một cơ sở mã cũ mà tôi cần phải cấu trúc lại bằng Java 8, vì vậy tôi có một giao diện, cho biết liệu trang web hiện tại của tôi có hỗ trợ nền tảng hay không.

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

và tôi có nhiều lớp thực hiện nó và mỗi lớp hỗ trợ một nền tảng khác nhau.

Một vài trong số các lớp thực hiện là:

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

}

Một cách thực hiện khác:

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

Trong thời gian chạy trong bộ lọc của tôi, tôi nhận được bean yêu cầu mà tôi muốn:

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

và gọi isPlatformSupportedđể biết liệu trang web hiện tại của tôi có hỗ trợ nền tảng sau hay không.

Tôi chưa quen với Java 8, vậy có cách nào để tôi có thể cấu trúc lại mã này mà không cần tạo nhiều lớp không? Vì giao diện chỉ chứa một phương thức, bằng cách nào đó tôi có thể sử dụng lambda để cấu trúc lại nó không?


1
Tạm gác sang một bên, chắc chắn: tất cả những gì bạn đang làm là một kiểm tra chứa trên một bộ. Tiêm tập hợp làm tham số hàm tạo.
Andy Turner

Câu trả lời:


5

Nếu bạn muốn bám sát thiết kế hiện tại, bạn có thể làm một cái gì đó như thế này:

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

}

Phương pháp này có một lợi thế là không tạo lớp cho mỗi loại (giảm giá, bsafe, v.v.), vì vậy điều này trả lời câu hỏi.

Tiến xa hơn, điều gì xảy ra nếu không có loại nào được yêu cầu, hiện tại nó sẽ thất bại vì bean không tồn tại trong ngữ cảnh ứng dụng - không phải là một cách tiếp cận thực sự tốt.

Vì vậy, bạn có thể tạo bản đồ loại cho tập hợp các nền tảng được hỗ trợ, duy trì bản đồ trong cấu hình hoặc một cái gì đó để mùa xuân làm điều kỳ diệu của nó. Bạn sẽ kết thúc với một cái gì đó như thế này:

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

Bây giờ nếu bạn làm theo phương pháp này, việc thêm một loại được hỗ trợ mới sẽ trở thành vô nghĩa, bạn chỉ thêm một cấu hình, cho đến nay, đây là phương pháp tốt nhất tôi có thể cung cấp.

Tuy nhiên, cả hai phương thức đều thiếu các tính năng java 8;)


4

Bạn có thể sử dụng các mục sau trong lớp cấu hình của mình, nơi bạn có thể tạo các 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);
    }
}

Ngoài ra, khi bạn muốn sử dụng đậu, một lần nữa rất dễ dàng:

@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

Như đã được viết trong câu trả lời của Mark Bramnik, bạn có thể chuyển nó sang cấu hình.

Giả sử rằng nó sẽ ở trong yaml theo cách đó:

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

Sau đó, bạn có thể tạo lớp cấu hình để đọc này:

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties
public class Config {

    private Map<String, List<String>> platforms = new HashMap<String, List<String>>();

    // getters and setters

Bạn có thể tạo trình xử lý với mã kiểm tra. Hoặc đặt nó trong bộ lọc của bạn như dưới đây:

@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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.