Strategy design template, generics and type of security

I want to create the following strategy template in conjunction with Factory, but I want it to be typical. I have done the following so far:

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, everything that I try, somewhere I will have an uncontrolled cast. Does anyone have an idea how I can refactor code for types?

Checking Effective Java I also came across 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 suggested by Ingo

 public <T> Collection<T> getResults(String query, Parser<T> p) 

but

 getResults("query", ParserFactory.APARSER); 

Or will it be better with listings?

+8
java generics strategy-pattern factory-pattern
source share
3 answers

I just pass the Parser<T> to the getResults() method and forget about this factory. See if you say:

 public <T> Parser<T> createParser(ParserType typ) { ... } 

you promise that the method will create a parser of any type that the caller wants. This is only possible in a safe way with parsers that return an empty collection. Moreover, you cannot return a Parser<String> from this function, because String does not match any type that the caller wanted to call.

If, however, you write:

  public <T> Collection<T> getResults(String query, Parser<T> parser) { ResultSet resultSet = getResultSet(query); //local private method Collection<T> results = parser.parse(resultSet); return results; } 

you have exactly what you wanted: the getResult method getResult not depend on how the parser works, and yet it returns a collection of the desired type.

And later instead

 Collection<String> it = (Collection<String>) getResults("query", APARSER); 

you speak:

 Collection<String> it = getResults("query", new AParser()); 

It is sound and makes sense.

+5
source share

I usually use this format. I know that many people do not like this, but so far no one has offered a better approach.

 public enum ParserType { APARSER(new AParser()); private Parser parser; // this should be an interface which is implemented by AParser private ParseType(Parser parser){ this.parser = parser; } public Parser getParserInstance() { return parser; } } 

You can pass Class objects if a new instance is required each time:

 public enum ParserType { APARSER(AParser.class); private Class<Parser> parserClass; private ParseType(Class<Parser> parserClass){ this.parserClass = parserClass; } public Parser createParser() { return parserClass.newInstance(); // TODO: handle exceptions here } } 

Note. I really want to find a better approach, so if you have thoughts, share them in a comment.

+3
source share

I welcome your desire to use a strategy template; +1 for this. I really think Ingo's comments are in place.

Just an additional comment (taken from Effective Java, 2nd Ed.):

  switch (parserType) { case APARSER: parser = new AParser(); break; } 

To use the words of Joshua Bloch, "this solution seems compact and even elegant." However, it can also be fragile and difficult to maintain. In general, you should try not to include enumeration constants, because whenever you do this, your code will break whenever you change the enumeration.

This is the right time to use the definition of an abstract method in your enumeration and place the code you want directly with the enumeration constant . This ensures that you will never forget to add the necessary linked enumeration code to your project and make sure that whenever you add to your list that your project will not break.

In fact, if your goals allow this, it may be possible or appropriate to transfer the entire factory method to your enumerator, and your enum class implements the Strategy interface.

+3
source share

All Articles