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.

有帮助吗?

解决方案

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.
许可以下: CC-BY-SA归因
scroll top