5

strategy pattern

I am considering using a strategy pattern for configuration file management, that way I can support some legacy configs. I feel pretty solid on the overall design (as its pretty standard strategy pattern), but I am curious if the client should know the type of strategy that is being implemented or if that violates the strategy pattern. Specifically the ConfigurationParser constructor requires an istream and a string (or maybe enum) of the type of stream it is (xml, json, ini, etc.) to know which concrete strategy to instantiate.

Ideally I would like to just pass the istream, but if I do that then I probably have to put in code in the ConfigurationParser to discern the stream type by looking for angle brackets vs square brackets or something of the sort.

I decided to not pass a string file path and determine type from extension because the legacy stuff isnt always consistent in extension naming and it makes my code a lot easier to test if I pass streams instead of hard coding file paths.

  • Which is more important to you: the ability to know what kind of stream it is so that you can process it properly, or the need for a higher degree of decoupling? – Robert Harvey Jul 10 '17 at 16:23
  • My gut reaction is the need for a higher degree of decoupling. – ÁEDÁN Jul 10 '17 at 16:26
  • Cool. So how will you solve the problem of processing the stream properly? Or is that largely irrelevant? – Robert Harvey Jul 10 '17 at 16:33
  • Haven't gotten that far. – ÁEDÁN Jul 10 '17 at 16:39
  • 1
    You might consider weighing the pros and cons, instead of just relying on your gut. High decoupling does you no good if the system can't perform its essential functions. I consider "correctness" of secondary importance. – Robert Harvey Jul 10 '17 at 16:40
4

I looks to me that you have two different problems. Problem A is easy to solve. But problem B is harder.

Problem A is to dynamically call a given strategy given a configString. That can be solved by creating a Map and pairing an instance of each parser with a string that identifies it. That way you just fetch from the Map the parser you need. If the parser is too costly to instantiate, you can put in the Map a builder for that parser instead. This solution assumes that the final user (or you) knows what type of configuration file is going to be parsed.

Obviously, to achieve total decoupling, a factory should set up the whole Map of parsers (or parser builder) and the client should have this Map passed to it. That way only the factory is hard coupled to the concrete parsers.

Problem B is that you want to automatically determine what kind of file (or istream) you are reading to use the appropiate parser, i.e., the final user (or you) will not select the file and tell the app the type of conf file.

A solution for problem B is to have all parsers in a List and iterate through it. When one parser fails to parse the stream, go to the next parser and so on. If a parser successfully parses the stream, end of story (you can report what parser you finally used if you add a name field to the parsers). If every parser fails then the file is not supported by any parser. You don't need to investigate inside the stream to guess the format, let the parsers try to parse it. One potential problem I see with this solution is that it is possible that two different parsers could interpret the same input format in different ways without failing. In that case the first parser that does will always do the work and it may not be the one you expected.

A log output could look like this:

Parsing: unknown_config_file
..not XML
..not JSON
..successfully parsed using "ini" parser.

or

Parsing: unknown_config_file
..not XML
..not JSON
..not ini
..unsuported config file.
  • 3
    Very good answer. Side note: if two different parsers could interpret the same input format in different ways without failing, not even a person can easily tell which format it is. Or, this person has additional information available, like context information or the file extension. Then this additional information can be passed to the ConfigurationParser's constructor as well. – Doc Brown Jul 10 '17 at 18:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.