So I’m learning to build a parser for a intro class for software design.
I have built a tokenizer package that splits my input string into Token objects that have getters for both the value and type. I can also return a raw String for value and type of the current token.
My public facing interface from the Tokenizer currently looks like this.
public Tokenizer(Grammar rules, String input) public Token getCurrentToken() {...} // Token has public getters similar to the two methods below public String getCurrentValue() {...} public String getCurrentType() {...} public void nextToken() throws InvalidTokenException {...} public void previousToken() {...}
In my Parser class I also have a TokenReceiver(interface) and a TokenizerAdapter class (implements Receiver and my specific tokenizer)
public void next(); public Token getToken(); public String getType(); public String getValue(); public Token getToken(); }
The rules are that each of the different steps in the parsing has to be done with different packages that are as loosely coupled as possible to any implementation details of the other packages, i.e. the parser should in theory work with any tokenizer I find(for example on Github), not just my own Tokenizer implementation, provided I just make an Adapter for it.
If I send back the Token objects from the Tokenizer then my parser will have to know about the Token objects (the getter methods specifically), which adds coupling to my Tokenizer implementation.
Sending back straight Strings for the value and type and then creating a another Token class in the Parser package and recreating Tokens objects feels instinctively wrong to me. Could an anonymous inner class for Token in the adapter class be a good solution?
I’m looking for what kind of patterns or concepts that can help me reference my Tokens from the Tokenizer while preserving a loose coupling to my specific tokenizer implementation.
Sorry if question is really stupid and the answer is really obvious, design patterns are still very abstract to me and we’re learning about so many of them I have a hard time knowing which one to use for different circumstances.
Advertisement
Answer
Have you considered the following
public interface Token { String getType(); String getValue(); } public interface Tokenizer { // either Iterable<Token> parse(String input); // or Stream<Token> parse(String input); } public class GrammarTokenizer implements Tokenizer { private final Grammar grammar; // constructor // method implementations }