簡體   English   中英

Java 8 帶附加參數的消費者

[英]Java 8 Consumer with additional parameters

我想編寫一個通用的 DTO 更新程序,它會更新它的一些屬性。 我的 object 看起來像這樣:

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

...我想使用一些 Java 8 函數/消費者特性來定義每個枚舉中的設置器。 我試過這樣的事情:

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

你能為我提供一個解決方案嗎? 它可以工作嗎? 我擔心傳入的值是動態的,因此它不適用於枚舉..

setter 方法是BiConsumer<T,U> ,其中T是 object 實例, 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));
}

根據定義, Consumer只接受一個參數。

由於您需要同時傳遞 object 來操作和新值,因此您必須使用允許傳遞兩個 arguments 的接口。 幸運的是,有BiConsumer接口

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

注意這里使用方法引用大致相當於寫成(p, fn) -> p.setFirstName(fn)

但是,這引入了一個小問題,因為您需要知道(並指定)參數的類型,並且您的枚舉希望具有混合類型(前兩個將返回BiConsumer<Person,String>而最后一個可能是BiConsumer<Person,Integer>

您需要一個BiConsumer可以使用目標 object 和新值:

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)

)

與其直接暴露消費者,不如考慮在枚舉中定義一個公共的assignset方法,並使消費者對外部不可見(信息隱藏):

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

然后調用FIRST_NAME.assign(person, "new name")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM