问题
I am trying to create a Holder class for different objects to be used in my application, I ended up with this code that works fine until some extent, the builder pattern works fine for the optional fields, but I guess this holder could be refactored to accept any arbitrarily number of parameter
package pojos;
public class Holder<T, R, S, U> {
private final T t;
private final R r;
private final S s;
private final U u;
private Holder(final Builder<T, R, S, U> builder) {
this.t = builder.t;
this.r = builder.r;
this.s = builder.s;
this.u = builder.u;
}
public T getField1() {
return this.t;
}
public R getField2() {
return this.r;
}
public S getField3() {
return this.s;
}
public U getField4() {
return this.u;
}
public static class Builder<T, R, S, U> {
private T t;
private R r;
private S s;
private U u;
public Builder field1(final T t) {
this.t = t;
return this;
}
public Builder field2(final R r) {
this.r = r;
return this;
}
public Builder field3(final S s) {
this.s = s;
return this;
}
public Builder field4(final U u) {
this.u = u;
return this;
}
public Holder<T, R, S, U> build() {
return new Holder<>(this);
}
public Builder<T, R, S, U> copy(final Holder<T, R, S, U> rowMappingsHolder) {
this.t = rowMappingsHolder.getField1();
this.r = rowMappingsHolder.getField2();
this.s = rowMappingsHolder.getField3();
this.u = rowMappingsHolder.getField4();
return this;
}
}
}
Example of usage:
protected Holder<Row, Map<Integer, String>, Void, Void> getRowMapHolder(Row row, Map<Integer,String> map) {
return (Holder<Row, Map<Integer, String>, Void, Void>) new Holder.Builder<Row, Map<Integer, String>,Void, Void>().field1(row).field2(map).build();
}
Any ideas?
Regards
~Marco
回答1:
How this should work for different number of parameters? You have finite number of accessors, so you cannot use, for example, h.getField2147(), if you don't declare it.
Another way to have a tuple for different number of objects is heterogeneous array. In Java, ofc, you may just use Object[] and you can wrap it with class, which have methods
public <T> T getField(int i) {
return (T) arr[i];
}
and then use like h.<String>getField(2147)
But creating different classes for tuples of different size (like your for 4 objects) is better.
回答2:
Thanks to Andy's comment and Google Autovalue, a good solution arose:
So we can create different classes that have meaning, no more "field1", "field2"...
package pojos;
import com.google.auto.value.AutoValue;
import org.apache.poi.ss.usermodel.Row;
import java.util.Map;
@AutoValue
public abstract class RowMapHolder {
public abstract Row row();
public abstract Map<Integer,String> mapping();
public static RowMapHolder create(Row row, Map<Integer, String> mapping) {
return new AutoValue_RowMapHolder(row, mapping);
}
}
or
package pojos;
import com.google.auto.value.AutoValue;
import java.util.List;
import java.util.Map;
@AutoValue
public abstract class KeyValuesMapHolder {
public abstract List<KeyValue<String,String>> keyValues();
public abstract Map<Integer,String> mapping();
public static KeyValuesMapHolder create(List<KeyValue<String, String>> keyValues, Map<Integer, String> mapping) {
return new AutoValue_KeyValuesMapHolder(keyValues, mapping);
}
}
来源:https://stackoverflow.com/questions/45862839/how-to-use-generics-properly-for-a-holder