首页 > 解决方案 > 使用函数式编程,提取提供子类对象的超类字段

问题描述

我有两个班动物和狗,即

public class Animal {
    private String name,age;
    //public getters and setters
}

public class Dog extends Animal {
    private String color;
    //public getters and setters
}

我正在使用 java 8 函数式编程从 json 节点中提取字段,即

public class EntityExtraction {

    private Function<JsonNode, Animal> extractAnimal = node -> {
         Animal animal = new Animal();
         animal.setName(node.get("name").asText()));
         animal.setAge(node.get("age").asText()));
         return animal;
    };

    private Function<JsonNode, Dog> extractDog = node -> {
        Dog dog = new Dog();
        dog.setName(node.get("name").asText()));
        dog.setAge(node.get("age").asText()));
        dog.setColor(node.get("color").asText()));
        return dog; 
    };

}

问题是它不是面向对象的。如果 Animal 类中有一个新字段,那么我必须在两个函数方法中显式地显示它,即 extractDog 和 extractAnimal。

有没有一种方法可以使用 extractDog 方法在 Dog 类中设置超类字段,而无需通过构造函数进行设置,例如

private Function<JsonNode, Dog> extractDog = node -> {
    Dog dog = new Dog();
    //extract superclass fields
    //dog.animal = extractAnimal.apply(node);
    dog.setColor(node.get("color").asText()));
    return dog;
};

标签: javainheritancejava-8

解决方案


您可以编写一个方法*,它会提供一个正确的实例以供进一步填充。

private <T extends Animal> T extractAnimal(JsonNode node, Supplier<T> animalSupplier) {
    T animal = animalSupplier.get();

    animal.setName(node.get("name").asText());
    animal.setAge(node.get("age").asText());

    return animal;
}

在你得到一个填充了Animal's 属性的对象后,你可以根据类型继续打包它:

Dog dog = extractAnimal(node, Dog::new);
dog.setColor(node.get("color").asText());
...
Cat cat = extractAnimal(node, () -> getPopulatedCat());

更新:

为避免重构,请extractAnimal(JsonNode node, Supplier<T> animalSupplier)从 Functional 方法中调用新方法,extractAnimal

private Function<JsonNode, Animal> extractAnimal = node -> extractAnimal(node, Animal::new);

*要遵循函数式范式,您不必只使用 Java 函数式类型进行操作。上述方法比私有Function字段更能雄辩地表达这个想法。


推荐阅读