I want to create the following Strategy Pattern combined with Factory, but I want it to be typesafe. I have done the following till now:
public interface Parser<T> {
public Collection<T> parse(ResultSet resultSet);
}
public class AParser implements Parser<String> {
@Override
public Collection<String> parse(ResultSet resultSet) {
//perform parsing, get collection
Collection<String> cl = performParsing(resultSet); //local private method
return cl;
}
}
public class ParserFactory {
public enum ParserType {
APARSER
}
public static <T> Parser<T> createParser(ParserType parserType) {
Parser<?> parser = null;
switch (parserType) {
case APARSER:
parser = new AParser();
break;
}
//unchecked cast happens here
return (Parser<T>) parser;
}
}
public class Context {
public <T> Collection<T> getResults(String query, ParserType parserType) {
ResultSet resultSet() = getResultSet(query); //local private method
Parser p = ParserFactory.createParser(parserType);
Collection<T> results = p.parse(resultSet)
}
}
In general whatever I attempt, somewhere I will have an unchecked cast. Anyone have an idea how I can refactor the code to be typesafe?
Checking Effective Java I also stumbled upon this pattern:
public final class ParserFactory {
private ParserFactory() {
}
private static class AParser implements Parser<String> {
@Override
public Collection<String> parse(ResultSet resultSet) {
//...
return new ArrayList<>();
}
}
public static final Parser<String> APARSER = new AParser();
}
So now I can use as Ingo suggested
public <T> Collection<T> getResults(String query, Parser<T> p)
as
getResults("query", ParserFactory.APARSER);
Or would this be better with enums?
createParser
method (or any other method) is supposed to create T out of thin air (so to speak). (Because this says literally: this method will give you a parser of any type, which can't be true). You must pass some input that has T, only then can the compiler check it. Conventionally, one would pass a Class<T>. – PetroglyphParserType.APARSER
would need to somehow provide a generic type argument ofString
. In other words it would ideally be<T> Parser<T> createParser(ParserType<T> parserType)
. But enums can't be generic, so it's a messy hand-off. – Ranson