How should I refactor my code in this case?
I'm currently using Qt's QTextStream to read many different types (read: different extension) of text files. Each "FileReader" class I create starts to have a similar pattern where it needs to readLine() like this:
// Get the line's first word as float where each word is delimited by a comma
fileData.readLine().split(",")[0].toFloat();
You can imagine I have tens of these lines in my program.
Further, it's possible that toFloat() could fail (e.g. the value read is not convertible to float), so I'm planning to modify the above line like this:
// Get the line's first word as float where each word is delimited by a comma
bool convertible;
fileData.readLine().split(",")[0].toFloat(&convertible);
if(!convertible) throw std::runtime_error("Error!");
Obviously, IMO, the least maintainable code would be to simply repeat the above code to every line that I use readLine(). This is definitely not the path I pla开发者_如何学Cn to choose. (I would welcome someone who could prove otherwise the benefits of doing so)
I could think of a few ways to refactor this code.
1) Instead of directly using Qt's QTextStream class, create my own class that owns QTextStream, and then create a method called readFirstTokenAsFloat(). Inside that method I would have error checking as shown above. Then every "FileReader" class would now switch to use this new class. The pros of this approach, IMO, is it accomplishes what I want to do, but the cons, IMO, is that if I were to need to do other things, or if I wanted to use other QTextStream's methods, I would violate the DRY principle (?) by duplicating the same methods, and internally just have a one-liner calling QTextStream.
2) OR I could just inherit from QTextStream. This way I would simply extend its functionality, and would also get all of QTextStream's functionality. But is inheritance a good idea in this case?
3) Any other thoughts? I'm sure someone has come across something like this. Is there a specific name for this pattern?
If you think you're using all QTextStream functionality, then inheritance is the way to go IMO. Inheritance is not a bad thing in itself, should just be avoided in some cases. But if there's at least a method in QTextStream which shouldn't be called at all, then this would probably lead to a weird design (perhaps using a interface would help in this case)
Now, if you're using a subset of the functionalities, then composition (approach number 1) is the way to go.
I would additionaly suggest to create an interface with the "readFirstTokenAsFloat()" method and whichever other method you want, and then implement the interface (and use it on your "FileReaders"). This way, you have a less coupled and easier to change design.
If something wasn't clear or was controversial, feel free to post in the comments, so we can improve the answer =).
class FileReaderBase {
protected:
QTextStream* fileData;
virtual float(readFirstTokenAsFloat);
}
Your FileReaders derive from that class so that they can use the same fileData. You can handle open in the constructor, close in destructor, e.g...
IMHO much better than subclassing into a framework. (favour composition over inheritance)
精彩评论