I’ve little experience with advanced OO practices, and I want to design this properly as an exercise. I’m thinking of implementing the following, and I’m asking if I’m going about this the right way.
I have a class PImage that holds the raw data and some information I need for an image file. Its header is currently something like this:
#include <boost/filesytem.hpp>
#include <vector>
namespace fs = boost::filesystem;
class PImage
{
public:
PImage(const fs::path& path, const unsigned char* buffer, int bufferLen) :
path_(path), filesize_(bufferLen),
data_(buffer, buffer + filesize_),
width_(0), height_(0) {}
const vector<char> data() const { return data_; }
const char* rawData() const { return &data_[0]; }
/*** other assorted accessors ***/
private:
fs::path path_;
int filesize_;
vector<char> data_;
int width_;
int height_;
}
I want to fill the width_ and height_ by looking through the file’s header. The trivial/inelegant solution would be to have a lot of messy control flow that identifies the type of image file (.gif, .jpg, .png, etc) and then parse the header accordingly.
Instead of using vector<char> data_, I was thinking of having PImage use a class, RawImageStream data_ that inherits from vector<char>. Each type of file I plan to support would then inherit from RawImageStream, e.g. RawGifStream, RawPngStream.
Each RawXYZStream would encapsulate the respective header-parsing functions, and PImage would only have to do something like height_ = data_.getHeight();.
- Am I thinking this through correctly?
- How would I create the proper
RawImageStreamsubclass fordata_to be in thePImagector? Is this where I could use an object factory? - Anything I’m forgetting?
Yes, you could implement your class hierarchy in the way you describe. Nevertheless, I would probably have had PngImage, GifImage and JpegImage derive directly from PImage. PImage can then become abstract:
Then, each concrete image type implements getWidth and getHeight.
The PImage class can then be created by a PImage factory:
In the factory, you pretty much open the file, look what type it has, and create the concrete image class passing the data in the constructor, to finally return the image as the abstract PImage.
Finally, I’d like to add that you should not worry too much about your design up front, and be ready to refactor later when you discover that your design does not fulfil your needs. That’s through trial and error that you will grow a feeling for what design is proper for your problem!