带有附加参数的Java8使用者

mpgws1up  于 2021-07-08  发布在  Java
关注(0)|答案(3)|浏览(366)

我想写一个通用的dto更新程序,更新它的一些属性。我的对象如下所示:

class Person {
    String firsName;
    String lastName;
    Integer age;
    setter/getter
}

我有一个枚举,它定义了哪些字段可以被覆盖:

enum OverriddenType {
    FIRST_NAME,
    LAST_NAME,
    AGE
}

而不是像这样做一个“硬编码”设置器。。。

public void override(Person person, Map<OverriddenType,Object> newValuesForProperties) {
    newValuesForProperties.forEach((type,value)) -> {
        if(type == OverriddenType.FIRST_NAME) {
            person.setFirstName((String)value);
        } else if(type == OverriddenType.LAST_NAME) {
            person.setLastName((String)value);
        } else if(type == OverriddenType.AGE) {
            person.setAge((Integer)value);
        }
    });
}

... 我想使用一些Java8函数/使用者特性来定义每个枚举中的setter。我试过这样的方法:

enum OverriddenType {
    FIRST_NAME(p -> p.setFirstName(???????)),  //don't know what to set here since the value is not here
    LAST_NAME(p -> p.setLastName(???????)),
    AGE(p -> p.setAge(???????));

    Consumer<Person> consumer;
    OverriddenType(Consumer<Person> consumer) {
        this.consumer = consumer;
    }
    public Consumer<Person> getConsumer();
}

但正如你所看到的,我不能在这里传递动态值。我也不知道逻辑会是什么样子,但我会想象这样的情况:

public void override(Person person, Map<OverriddenType,Object> newValuesForProperties) {
    newValuesForProperties.forEach((type,value)) -> 
        type.getConsumer().accept(person, value) // this doesn't exist, but I can imagine some additional parameter passing
    );
}

你能给我一个解决办法吗?它能工作吗?我担心传入的值是动态的,因此它对枚举不起作用。。

41zrol4v

41zrol4v1#

setter方法是 BiConsumer<T,U> ,在哪里 T 是对象示例,并且 U 是值。

enum OverriddenType {
    FIRST_NAME((person, value) -> person.setFirsName((String) value)),
    LAST_NAME ((person, value) -> person.setLastName((String) value)),
    AGE       ((person, value) -> person.setAge((Integer) value));

    private final BiConsumer<Person, Object> setter;

    private OverriddenType(BiConsumer<Person, Object> setter) {
        this.setter = setter;
    }

    public void override(Person person, Object value) {
        this.setter.accept(person, value);
    }
}
public void override(Person person, Map<OverriddenType, Object> newValuesForProperties) {
    newValuesForProperties.forEach((type, value) -> type.override(person, value));
}
vm0i2vca

vm0i2vca2#

根据定义a Consumer 只接受一个论点。
由于需要同时传递要操纵的对象和新值,因此必须使用允许传递两个参数的接口。幸运的是有 BiConsumer 接口。

BiConsumer<Person, String> personFirstNameSetter = Person::setFirstName;

请注意,这里使用方法引用大致相当于编写 (p, fn) -> p.setFirstName(fn) .
但是,这会带来一个小问题,因为您需要知道(并指定)参数的类型,并且您的枚举希望具有混合类型(前两种类型将返回 BiConsumer<Person,String> 最后一个可能 BiConsumer<Person,Integer> .

ruyhziif

ruyhziif3#

你需要一个 BiConsumer 它可以使用目标对象和新值:

enum OverriddenType {
    FIRST_NAME((p, v) -> p.setFirstName(v)),
    LAST_NAME((p, v) -> p.setLastName(v)),
    AGE((p, v) -> p.setAge(v));

    BiConsumer<Person> consumer;
    OverriddenType(BiConsumer<Person, Object> consumer) {
        this.consumer = consumer;
    }

    public BiConsumer<Person> getConsumer();
}

(如果您的setter接受 Object ,甚至可以使用方法引用:

OBJECT(Person::setObject)

)
与其直接暴露消费者,不如考虑定义一个公共 assign 或者 set 方法并使使用者对外不可见(信息隐藏):

public void assign(final Person target, final Object newValue) {
  this.consumer.accept(target, newValue);
}

然后打电话给 FIRST_NAME.assign(person, "new name") .

相关问题