Генераторы Java + шаблон Builder
Как мне позвонить start()
ниже?
package com.example.test;
class Bar {}
public class Foo<K>
{
final private int count;
final private K key;
Foo(Builder<K> b)
{
this.count = b.count;
this.key = b.key;
}
public static class Builder<K2>
{
int count;
K2 key;
private Builder() {}
static public <K3> Builder<K3> start() { return new Builder<K3>(); }
public Builder<K2> setCount(int count) { this.count = count; return this; }
public Builder<K2> setKey(K2 key) { this.key = key; return this; }
public Foo<K2> build() { return new Foo(this); }
}
public static void main(String[] args)
{
Bar bar = new Bar();
Foo<Bar> foo1 = Foo.Builder.start().setCount(1).setKey(bar).build();
// Type mismatch: cannot convert from Foo<Object> to Foo<Bar>
Foo<Bar> foo2 = Foo.Builder<Bar>.start().setCount(1).setKey(bar).build();
// Multiple markers at this line
// - Bar cannot be resolved
// - Foo.Builder cannot be resolved
// - Syntax error on token ".", delete this token
// - The method start() is undefined for the type Foo<K>
// - Duplicate local variable fooType mismatch: cannot convert from Foo<Object> to Foo<Bar>
Foo<Bar> foo3 = Foo<Bar>.Builder.start().setCount(1).setKey(bar).build();
// Multiple markers at this line
// - Foo cannot be resolved
// - Syntax error on token ".", delete this token
// - Bar cannot be resolved
}
}
Ответы
Ответ 1
Вы были близки:
Foo.Builder.<Bar> start().setCount(1).setKey(bar).build();
Ура!:)
P.S. Если компилятор не может вывести параметр типа метода самостоятельно, вы можете принудительно его вызвать, вызвав obj.<Type> method(...)
.
P.P.S вы можете использовать:
public Foo<K2> build() {
return new Foo<K2>(this);
}
Избегайте использования необработанных типов.
Ответ 2
Метод Андрея в порядке, но большинство программистов, вероятно, будут бороться с довольно неизвестным синтаксисом. Это может быть проще использовать следующим образом:
static public <K3> Builder<K3> start(Class<K3> cls) { return new Builder<K3>(); }
Foo<Bar> foo1 = Foo.Builder.start(Bar.class).setCount(1).setKey(bar).build();
Класс передается только для помощи с общим типом. Это не очень, но, по крайней мере, синтаксис является общеизвестным.
Другой вариант - сразу начать с объекта общего типа:
Foo<Bar> foo1 = Foo.Builder.startWithKey(bar).setCount(1).build();
Ответ 3
Это моя реализация шаблона generic builder в java 8.
public class Builder<T> {
private T instance;
private boolean ifCond = true; // default
public Builder(Class<T> clazz){
try {
instance = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
public Builder<T> with(Consumer<T> setter){
if(ifCond)
setter.accept(instance);
return this;
}
public T get(){
return instance;
}
public static <T> Builder<T> build(Class<T> clazz) {
return new Builder<>(clazz);
}
public Builder<T> If(BooleanSupplier condition){
this.ifCond = condition.getAsBoolean();
return this;
}
public Builder<T> endIf(){
this.ifCond = true;
return this;
}
}
How to use it:
List list = Arrays.asList(1, 2, 3, 4, 5)
System.out.println(
Builder.build(Sample.class)
.with(s -> s.setId(1))
.with(s -> s.setName("Sample object"))
.with(s -> s.setList(list))
.get()
);
// Java Properties
System.out.println(
Builder.build(Properties.class)
.with(p -> p.put("one", 1))
.with(p -> p.put("two", 2))
...
.get()
);
System.out.println(Builder.build(Properties.class)
.with(p -> p.put("one", 1))
.If(() -> false) // any expression return boolean
.with(p -> p.put("two", 2))
.with(p -> p.put("three", 3))
.endIf()
.with(p -> p.put("four", 4))
.get()
); // output=> {one=1, four=4}
https://howtocodetutorial.wordpress.com/generic-builder-pattern-in-java-8/