What Design to choose for Parsing different files to populate different classes?
https://softwareengineering.stackexchange.com/questions/359237
-
21-01-2021 - |
سؤال
I am currently working on project which requires parsing different types of files. The content of the files will populate the classes.
eg: file1 populate content of class1, file2 populate content of class2, etc.
My question is where should the parsing logic of the file go?
1st option
: If I place the parsing logic inside the class then the class becomes really huge, because currently the class itself is ~400 lines and will grow in the future. The advantage of this way is things are really simple, I could use operator>>, etc.
2nd option
: Create a new class that takes std::istream
and class reference, do the parsing logic there and populate the class. The advantage of this way of doing is that if the class remains the same but formatting of the file changes,
eg: `file1 populate content of class1 or file1-v2 populate content of class1`
I have to use polymorphism to change the parsing logic and keep the design simple. Disadvantage of this option is, it's a little complex but I can live with it.
Which option do you think is better or is there any other better option?
المحلول
Classes should have a single responsibility. Presumably the responsibility of parsing a file to populate a class and the responsibilities of class itself are distinct and should not be combined. Therefore the 2nd option is the better design.
It's pretty common for file formats to change as a system develops, and by separating this concern now, you'll be in a good place if the file format or the class you're populating changes. It's also a design that allows greater flexibility--e.g. if you decide you want to populate your class from the network, a different file format, etc.
نصائح أخرى
If the parsing is more complex than a few lines of code, it is probably better to put it into separate classes, lets call them Class1Parser
, Class2Parser
and so on. If those classes contain similar parts, you can either
create a common base class
BaseParser
for both where the reusable parts livecreate a separate utility class
ParserUtil
for reusable functionsmake the parser a generic class like
Parser<T>
where T is eitherClass1
orClass2
use a combination of the former options (like making only the
ParserUtil
orBaseParser
generic)
Note that an inheritance hierarchy of the parsers now can be independent from the inheritance hierarchy of the parsed classes, this would not quite be possible by putting the parsing logic directly into Class1
/Class2
.
None of these options should hold you back from implementing an operator>>
for Class1
or Class2
, if you think you need it for ease of use. This operator can simply delegate its functionality to an object of type Class1Parser
or Class2Parser
.
If these approaches end up becoming more complex than putting the parser logic into Class1
or Class2
, then there is something utterly wrong in your code. In essence, it should actually be the same logic. By putting the parsing logic into separate classes, it stays decoupled from other methods in those classes, which should reduce the overall complexity, not increase it.