问题
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