How to use generics properly for a Holder

我的梦境 提交于 2019-12-11 04:33:38

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!