Java 8:在一个对象上应用方法列表

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

Java 8: Applying a list of methods on one object

问题

我在代码中有一个特定的部分我想做的就是下面这样但我不知道如何编写以避免代码重复是否有一种方法我可以声明一个方法列表然后将其应用于`productFeatureValidationDto`。我目前的方法很新手

public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(ProductFeatureValidationDto productFeatureValidationDto) throws
        ApplicationException, ParseException {
    ValidateProductFeatureResponse response;

    List<Function<ProductFeatureValidationDto, ValidateProductFeatureResponse>> validationMethods = new ArrayList<>();
    validationMethods.add(this::validateProductFeatureA);
    validationMethods.add(this::validateProductFeatureB);
    validationMethods.add(this::validateProductFeatureC);
    validationMethods.add(this::validateProductFeatureD);
    validationMethods.add(this::validateProductFeatureE);
    validationMethods.add(this::validateProductFeatureF);

    for (Function<ProductFeatureValidationDto, ValidateProductFeatureResponse> method : validationMethods) {
        response = method.apply(productFeatureValidationDto);
        if (response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())) {
            return response;
        }
    }

    return getResponseOnValidationSuccess(productFeatureValidationDto);
}
英文:

I have a particular part in code where all I want to do is the below, but I am at a loss to write in a way that doesn't involve code repetition. Is there a way that I can declare a list of methods, which can be then applied to productFeatureValidationDto. My current approach is noob-ish.

public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(ProductFeatureValidationDto productFeatureValidationDto) throws
        ApplicationException, ParseException {
    ValidateProductFeatureResponse response;
    response = this.validateProductFeatureA(productFeatureValidationDto);
    if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
        return response;
    }
    response = this.validateProductFeatureB(productFeatureValidationDto);
    if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
        return response;
    }
    response = this.validateProductFeatureA(productFeatureValidationDto);
    if(response.getStatus().equalsIgnoreCase(MPResponseStatus.FAILURE.name())){
        return response;
    }
    response = this.validateProductFeatureC(productFeatureValidationDto);
    if(response.getStatus().equalsIgnoreCase(MPResponseStatus.FAILURE.name())){
        return response;
    }
    response = this.validateProductFeatureD(productFeatureValidationDto);
    if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
        return response;
    }
    response = this.validateProductFeatureE(productFeatureValidationDto);
    if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
        return response;
    }
    response = this.validateProductFeatureF(productFeatureValidationDto);
    if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
        return response;
    }
    return getResponseOnValidationSuccess(productFeatureValidationDto);
}

Thanks in advance.

答案1

得分: 0

如果您能够使用Spring框架
首先您可以定义一个类似这样的接口
```java
public interface ValidateProduct{
    ValidateProductFeatureResponse validate(ProductFeatureValidationDto dto);
}

您的具体验证类实现了这个接口并注册到Spring上下文中。

public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(ProductFeatureValidationDto productFeatureValidationDto) throws
        ApplicationException, ParseException {
    ValidateProductFeatureResponse response;
    Map<String, ValidateProduct> beansOfType = applicationContext.getBeansOfType(ValidateProduct.class);
    for (ValidateProduct value : beansOfType.values()) {
        response = value.validate(productFeatureValidationDto);
        if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
            return response;
        }
    }
    return getResponseOnValidationSuccess(productFeatureValidationDto);
}

<details>
<summary>英文:</summary>

if you can use spring framework.  
at first you can define an interface like this.
```java
public interface ValidateProduct{
    ValidateProductFeatureResponse validate(ProductFeatureValidationDto dto);
}

Your specific verification class implements this interface and register to srpingcontext

public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(ProductFeatureValidationDto productFeatureValidationDto) throws
        ApplicationException, ParseException {
    ValidateProductFeatureResponse response;
    Map&lt;String, ValidateProduct&gt; beansOfType = applicationContext.getBeansOfType(ValidateProduct.class);
    for (ValidateProduct value : beansOfType.values()) {
        response = value.validate(productFeatureValidationDto);
        if(response.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name())){
            return response;
        }
    }
    return getResponseOnValidationSuccess(productFeatureValidationDto);
}

答案2

得分: 0

我建议采取以下方法(示意图):

    /**
     * 验证函数列表
     */
    private final static List<Function<ProductFeatureValidationDto, ProductFeatureValidationDto>> VALIDATIONS = new LinkedList<>();

    /**
     * 填充验证列表
     */
    static {
        VALIDATIONS.add((source) -> {
            // 针对特性 A 的测试
            return source;
        });
        VALIDATIONS.add((source) -> {
            // 针对特性 B 的测试
            return source;
        });
        VALIDATIONS.add((source) -> {
            // 针对特性 C 的测试
            return source;
        });
    }

    /**
     * 失败判定的断言
     */
    private final Predicate<ProductFeatureValidationDto> IS_FAILURE = (dto) ->
            dto.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name());

    /**
     * 验证方法
     */
    public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(
            ProductFeatureValidationDto dto
    ) throws ApplicationException, ParseException {

        // 遍历验证函数并在 dto 实例上调用它们
        // 根据失败的验证筛选流
        // 在第一个匹配时停止
        Optional<ProductFeatureValidationDto> dtoOptional = VALIDATIONS.stream()
                .map(action -> action.apply(dto))
                .filter(IS_FAILURE)
                .findFirst();

        // 根据结果应用失败/成功映射
        return dtoOptional.isPresent()
                ? getResponseOnValidationFailure(dto)
                : getResponseOnValidationSuccess(dto);
    }
英文:

I would suggest following approach (schematic):

    /**
     * List of validation functions
     */
    private final static List&lt;Function&lt;ProductFeatureValidationDto, ProductFeatureValidationDto&gt;&gt; VALIDATIONS = new LinkedList&lt;&gt;();

    /**
     * Fill validations list
     */
    static {
        VALIDATIONS.add((source) -&gt; {
            // test for feature A
            return source;
        });
        VALIDATIONS.add((source) -&gt; {
            // test for feature B
            return source;
        });
        VALIDATIONS.add((source) -&gt; {
            // test for feature C
            return source;
        });
    }
    
    /**
     * Predicate for failure determination
     */
    private final Predicate&lt;ProductFeatureValidationDto&gt; IS_FAILURE = (dto) -&gt;
            dto.getStatus().equalsIgnoreCase(ResponseStatus.FAILURE.name());

    /**
     * Validation method
     */
    public ValidateProductFeatureResponse validateProductFeatureAgainstAllCriteria(
            ProductFeatureValidationDto dto
    ) throws ApplicationException, ParseException {
        
        // iterate over validation functions and invoke them on dto instance
        // filter stream by failed validations
        // stop on first match
        Optional&lt;ProductFeatureValidationDto&gt; dtoOptional = VALIDATIONS.stream()
                .map(action -&gt; action.apply(dto))
                .filter(IS_FAILURE)
                .findFirst();
        
        // apply fuilure / success maping depending on result
        return dtoOptional.isPresent()
                ? getResponseOnValidationFailure(dto)
                : getResponseOnValidationSuccess(dto);
    }

答案3

得分: 0

以下是翻译好的内容:

我最终是根据 @Eiden 和 @Alexandra Dudkina 给出的答案来组合我的解决方案的。非常感谢他们。以下是我整个解决方案的要点。

所以,我有两个接口:

  1. IProductFeature:这是一个功能接口,只有一个方法 validate。每个约束都需要实现这个接口。
  2. IProductValidationService:这是一个约定,指定了需要实现的核心方法。方法 validateProductFeatureAgainstAllCriteria 是约定的一部分。

有一个配置文件,将所有的功能导入并按照不同类型的产品进行了组织成列表。这个列表已经被保存在一个以产品类型为键的映射中。因此,这就像一个工厂,根据给定的产品类型提供了一个约束列表。

实现 IProductValidationService 的具体类从配置中获取列表,然后将列表中的所有约束应用于给定的数据传输对象(dto)。通过这种方式,我将所有关注点分离到了不同的部分。
这种方法的实际优势包括:

  • 您可以为单个功能编写广泛的测试用例和文档。
  • 如果将来在 ProductFeatureB(例如)中有政策变更,我只需要创建一个新的具体类,称其为 ProductFeatureBV2,并仅更改配置文件。政策变更可以作为类注释的一部分进行记录。这样,在不改变核心验证方法的情况下,我可以废弃 ProductFeatureB。这使得代码变得非常灵活。

非常感谢社区帮助我正确地完成这个任务。如果还有进一步的改进建议,请提出。

英文:

I ended up composing my solution from the answers given by @Eiden and @Alexandra Dudkina. A big shoutout to them. Below is the crux of my whole solution.

So, I have two interfaces

  1. IProductFeature : This is a functional interface which has only one method validate. Every constraint needs to implement this.
  2. IProductValidationService: This is a contract specifying the core methods needed to be implemented. The method validateProductFeatureAgainstAllCriteria is part of the contract.

There is a config file where all the features have been imported and organised into lists as required for different kinds of products. This list has been kept in a map with the product type as key. So this is acting like a factory which is giving a list of constraint based on a given product type.

The concrete class implementing IProductValidationService gets the list from the config and then applies all the constraints in the list to the given dto.
This way, I have separated all the concerns into separate portions.
The practical advantages to this approach are:

  • You can write extensive test cases and documentation for individual features.
  • If in the future, there is a policy change in ProductFeatureB(for e.g.),all I have to do is create a new concrete class, call it ProductFeatureBV2 and change only config file. The policy changes can be documented as part of the class javadoc. This way without changing core validation method, I can deprecate ProductFeatureB. This makes the code extremely flexible.

Thanks a lot to the community for helping me getting this right. If there are further improvements to be made here, please suggest them.

huangapple
  • 本文由 发表于 2020年9月15日 07:39:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63893132.html
匿名

发表评论

匿名网友

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

确定