I have a problem with understanding of some basic OOP concepts. I’ll try to describe it with an example. Let’s say I have an application which should draw figures of different shapes.
I create a Figure class and add a field Shape (which is kind of enumeration and can be Shape.Circle or Shape.Square).
public class Figure {
public Shape shape;
public void draw() {
if( shape == Shape.Square )
// draw a square
else if( shape == Shape.Circle )
// draw a circle
}
}
When I need to add more shapes to my application I have to add more ifs to draw() method. I think it’s bad.
I can make Figure class abstract (or make it an interface), inherit figures of concrete shape from this class and override draw() method.
public abstract Figure { void draw(); }
public class Circle extends Figure {
@Override public void draw() {
// draw a circle
}
}
// same for Square
When I need new shape I just add new class.
Next I decide I want to have a color for my figures: Black or White. Black square and white square should be drawn differently. The problem looks the same. I can add color field to Figure class and deal with ifs in each draw method or create classes like BlackCircle, BlackSquare, WhiteCircle, WhiteSquare.
Later if I decide to add another property for Figure (let’s say Size which can be Small, Medium or Large) I have to create 2 * 2 * 3 classes like BigBlackCircle, SmallWhiteSquare and so on. And I can’t change figure’s color or shape in runtime. I think it’s not the right way.
Trying to understand the problem I found out that I can still have single class for all figures. Then I store color, shape, size as fields and add kind of DisplayManager class responsible for drawing. I can have different implementations of DisplayManager for different drawing algorithms.
public class Figure {
public Shape shape;
public Color color;
public Size size;
public DisplayManager display;
public void draw() {
display.draw(this);
}
}
public class DisplayManager {
public void draw( Figure figure ) {
// drawing based on figure's shape, color and size
}
}
But this way I come back to the problem from step 1: I have to deal with a lot of ifs in draw() method. Could anyone explain the correct way here? How should I design the classes to save flexibility of my application?
Instead of declaring
DisplayManager.draw(Figure), declareFigure.draw(DisplayManager). Implement forDisplayManagersome methods so it could be used fromFigure[drawPoint(), drawLine(),….]And for each extension of
Figure, implement its owndraw(DisplayManager)which uses the specific instance of givenDisplayManager