Object Oriented Programming Explained - Part 2 - Polymorphism
Let's say we have a system that needs to be able to render images (jpg, gif, png, etc..) to a window and there is nothing written that does this yet. We know each different file type is an image, but they all use different encodings. This is a perfect case for polymorphism. We have a common goal (display all images to the window) but different types of images to display with different algorithms needed for each.
Class Image {
private File imageFile;
private ImageType imageType;
// constructor - called on new()
public Image(File imageFile) {
this.imageFile = imageFile;
if (imageFile.extension == "JPG") {
imageType = ImageType.JPEG;
} else if (imageFile.extension == "GIF") {
imageType = ImageType.GIF;
} else if (imageFile.extension == "PNG") {
imageType = ImageType.PNG;
}
}
// returns the type of image this is
public ImageType getImageType() { return imageType; }
// gets the appropriate image renderer for this image type
public ImageRenderer getImageRenderer() {
if (imageType == ImageType.JPEG) {
return new JpegRenderer(imageFile);
} else if (imageType == ImageType.GIF) {
return new GifRenderer(imageFile);
} else if (imageType == ImageType.PNG) {
return new PngRenderer(imageFile);
}
}
// this is the abstract class for an image renderer. It can not render anything by itself.
Abstract Class ImageRenderer {
public ImageRenderer(File imageFile) {
this.imageFile = imageFile;
}
public void renderImage() {
Data data = readDataFromDisk(imageFile);
renderImageData(data);
}
protected abstract void renderImageData(Data imageData);
protected Data readDataFromDisk(File imageFile) {
//read bytes, common file operation...
return data;
}
}
Class JpegRenderer extends ImageRenderer {
protected void renderImage(Data imageData) { // Jpeg Specific Decoding Here }
}
Class GifRenderer extends ImageRenderer {
protected void renderImage(Data imageData) { // Gif Specific Decoding Here }
}
Class PngRenderer extends ImageRenderer {
protected void renderImage(Data imageData) { // Png Specific Decoding Here }
}
Image Rendering Code:
// point to the image file the user specified
File imageFile = new File ("/path/to/some/user/image/file");
// create a new "image" based on this
Image image = new Image(imageFile);
// get the renderer for the image
ImageRenderer renderer = image.getImageRenderer();
// render the image
renderer.renderImage();
Read through the code and pay particular attention to how simple the Image Rendering part is. All that's done from that point is an image is loaded, the render is referenced and invoked. From that point it looks very, very simple and that's because all of the hard parts are abstracted out and delegated to their own classes which handle the more complex stuff. From here you can see that all that's required to finish this implementation is to get a working decoding algorithm for each image type and put them in the respective ImageRenderers.
This works because we knew the common things about an image were that they are able to be rendered onto the screen. The type of file is chosen when an Image is instantiated and the Renderer is picked based on that. This is extensible because to add support for additional image types, you just need to add an ImageRenderer supporting it and add a few lines in to the Image class.
This sort of abstraction is the basis of polymorphism. ImageRenderer is the polymorphic class here, not Image. It is a design decision to implement it that way, as I'm sure some would prefer to also abstract out Image and then have JpegImage, GifImage, PngImage, etc. That's not entirely necessary as the only difference at that level is which renderer is called, because again, all of the difficult and unique work is performed in the Renderer.
To understand this better, say to yourself, "Only an ImageRenderer is needed. All ImageRenderers Render Images. A JpegRenderer IS an ImageRenderer so it can Render Images."
Organization is key here. It doesn't matter that I haven't filled out the decoding sections. We all know that it's a bunch of algorithms that decode the file and turn it into RGB data. The design is what's important.
Related Articles:
Object Oriented Programming Explained - Part 1 - The Basics
How to start writing software: Web Applications
How I became a professional software developer
Categories
Editorials3 TrackBacks
Listed below are links to blogs that reference this entry: Object Oriented Programming Explained - Part 2 - Polymorphism.
TrackBack URL for this entry: http://www.rbgrn.net/blog/mt/mt-tb.cgi/53
Object Oriented (OO) languages are a staple of the development community, however many people continue to argue against them, citing that they are inefficient, useless, confusing and unnecessary. There are many real benefits to using OO even for ... Read More
Hibernate is an excellent tool which saves many projects from substantial amounts of code. Gone are the days of writing massive datasource layers full of obnoxious JDBC code. As gravy you also get simple query objects, caching, connection p... Read More
If you have a need to use the command pattern and want to have a standard interface but with type safe parameters, I have come up with a solution. This is one of the most interesting uses (or hacks) of... Read More



from my point of view you're violating SRP in your example and also you created a dependency between image and imagerenderer and that is not a good practice.
I don't understand why you mix factory for creating imagerenderer inside Image class.
I believe you are looking a little too deep into my "designs." This was an example that I typed out just to show how Polymorphism works, not to show best practices or anything else.