由于双花括号通常应避免使用,因此您可以创建一个非常简单和通用的“builder”类,以某种惯用方式设置属性。
注意:我称该类为"Bean"或POJO,以遵循JavaBean标准:什么是JavaBean?。不管怎样,我主要会使用这个类来初始化Javabeans。
Bean.java
public class Bean<T> {
private T object;
public Bean(Supplier<T> supplier) { object = supplier.get(); }
public Bean(T object) { this.object = object; }
public T set(Consumer<T> setter) {
setter.accept(object);
return object;
}
}
这个Bean类的实例可以从现有对象创建或使用Supplier生成。该对象存储在字段object
中。set方法是一个高阶函数,接受另一个函数--Consumer<T>
。消费者接受一个参数并返回void。这将在新范围内创建setter副作用。
Bean .set(...)
方法返回object
,可以直接在赋值中使用。
我喜欢这种方法,因为对象的赋值包含在封闭块中,感觉就像在创建对象之前设置属性,而不是创建对象并对其进行变异。
最终结果是创建新Java对象的一种不错的方式,但与C#对象初始化程序相比仍然有点冗长。
以下是使用该类的示例:
Rectangle rectangle = new Bean<>(Rectangle::new).set($ -> {
$.setLocation(0, 0);
$.setBounds(0, 0, 0, 0);
});
如果您有嵌套的项目,最好根据名称命名变量。Java不允许重用$
,因为它存在于外部作用域中,没有阴影。
Rectangle rectangle3 = new Bean<>(new Rectangle()).set(rect-> {
rect.setLocation(-50, -20);
rect.setBounds(new Bean<>(Rectangle::new).set(innerRect -> {
innerRect.setLocation(0, 0);
innerRect.setSize(new Bean<>(Dimension::new).set(dim -> {
dim.setSize(640, 480);
}));
}));
});
现在比较普通代码。
Rectangle rectangle4 = new Rectangle();
rectangle4.setLocation(-50, -20);
Rectangle innerRect = new Rectangle();
innerRect.setLocation(0, 0);
Dimension dimension = new Dimension();
dimension.setSize(640, 480);
innerRect.setSize(dimension);
rectangle4.setBounds(innerRect);
另外,您可以编写一个接受 void
并返回所需对象的 lambda,并将其强制转换为 Supplier<DesiredType>
,然后立即调用 .get()
。这不需要单独的类,但您必须自己创建 bean。
Rectangle rectangle5 = ((Supplier<Rectangle>)() -> {
Rectangle rect = new Rectangle();
rect.setLocation(0, 0);
return rect;
}).get();
实用性说明:由于在嵌套元素时无法重复使用$
,因此这种方法仍然有点冗长。变量名称开始变得很长,任何语法吸引力都消失了。
还有一点需要注意的是,滥用set()方法可以在闭包内创建对象实例。正确使用时,唯一的副作用应该是在你正在创建的对象上。
还有一个注意事项:这只是为了好玩。不要在生产中使用它。