Java 8个带有附加参数的消费者
Java 8 Consumer with additional parameters
我想写一个通用的 DTO 更新器,它更新它的一些属性。我的对象看起来像这样:
class Person {
String firsName;
String lastName;
Integer age;
setter/getter
}
我有一个枚举,它定义了哪些字段可以被覆盖:
enum OverriddenType {
FIRST_NAME,
LAST_NAME,
AGE
}
而不是像这样“硬编码”setter...
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 Function/Consumer 特性来定义每个枚举中的 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
);
}
你能给我一个解决方案吗?能行吗?恐怕传入值是动态的,因此它不适用于枚举..
根据定义,Consumer
只接受一个参数。
由于您需要同时传递要操作的对象和新值,因此您必须使用允许传递两个参数的接口。幸运的是,有 the BiConsumer
interface。
BiConsumer<Person, String> personFirstNameSetter = Person::setFirstName;
注意这里使用方法引用大致相当于写(p, fn) -> p.setFirstName(fn)
.
但是,这会引入一个小问题,因为您需要知道(并指定)参数的类型,并且您的枚举希望具有混合类型(前两个 return BiConsumer<Person,String>
最后一个可能 BiConsumer<Person,Integer>
.
一个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));
}
你需要一个可以消费目标对象和新值的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)
)
与其直接暴露消费者,不如考虑在枚举中定义一个 public assign
或 set
方法并使消费者对外部不可见(信息隐藏):
public void assign(final Person target, final Object newValue) {
this.consumer.accept(target, newValue);
}
然后调用 FIRST_NAME.assign(person, "new name")
.
我想写一个通用的 DTO 更新器,它更新它的一些属性。我的对象看起来像这样:
class Person {
String firsName;
String lastName;
Integer age;
setter/getter
}
我有一个枚举,它定义了哪些字段可以被覆盖:
enum OverriddenType {
FIRST_NAME,
LAST_NAME,
AGE
}
而不是像这样“硬编码”setter...
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 Function/Consumer 特性来定义每个枚举中的 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
);
}
你能给我一个解决方案吗?能行吗?恐怕传入值是动态的,因此它不适用于枚举..
根据定义,Consumer
只接受一个参数。
由于您需要同时传递要操作的对象和新值,因此您必须使用允许传递两个参数的接口。幸运的是,有 the BiConsumer
interface。
BiConsumer<Person, String> personFirstNameSetter = Person::setFirstName;
注意这里使用方法引用大致相当于写(p, fn) -> p.setFirstName(fn)
.
但是,这会引入一个小问题,因为您需要知道(并指定)参数的类型,并且您的枚举希望具有混合类型(前两个 return BiConsumer<Person,String>
最后一个可能 BiConsumer<Person,Integer>
.
一个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));
}
你需要一个可以消费目标对象和新值的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)
)
与其直接暴露消费者,不如考虑在枚举中定义一个 public assign
或 set
方法并使消费者对外部不可见(信息隐藏):
public void assign(final Person target, final Object newValue) {
this.consumer.accept(target, newValue);
}
然后调用 FIRST_NAME.assign(person, "new name")
.