K
kpg
Hi all,
I'm having difficulty coming up with a design that I like for this
particular problem. He's the deal:
I have an abstract class and a set of concrete subclasses based on that
class, typical abstract class factory pattern. The abstract class is a
shape class, and the subclasses are types of shapes, circle, square,
arc, and so on.
I read an xml file which defines the shapes, it looks as expected:
<shapes>
<circle>
<x>0</x>
<y>0</y>
<radius>0</radius>
</circle>
... mode shapes here
</shapes>
So as I process the xml, I find out what kind of shape I need, I create
it and set the shape's properties based on the xml. The shape is then
added to a shape collection for later use.
Here is the class definition:
public abstract class Shape
{
public int x;
public int y;
}
public class Circle : Shape
{
public int radius;
}
public class Arc : Circle
{
public int start;
public int sweep;
}
public class Square : Shape
{
public int width;
public int height;
}
Now, I could have a case statement and do this:
//case need to build a circle
Circle myCircle = new Circle();
myCircle.x = 0;
myCircle.y = 0;
myCircle.radius = 15;
//case need to build an arc
Arc myArc = new Arc();
myArc.x = 0; //duplicate code
myArc.y = 0; //duplicate code
myArc.radius = 15; //duplicate code
myArc.start = 90;
myArc.sweep = 180;
//case need to build a Square
Square mySquare = new Square();
mySquare.x = 0; //duplicate code
mySquare.y = 0; //duplicate code
mySquare.width = 20;
mySquare.height = 40;
But this seems inefficient, all shapes have an x and y (at least) and
it needs to be set each time for each subclass.
So I could use a class factory and do this:
Shape myShape;
myShape = ShapeFactory(); //assume this retunrs the appropriate class
myShape.x = 0;
myShape.y = 0;
if (myShape is Circle)
{
Circle myCircle = (Circle)myShape; //downcast
myCircle.radius = 15;
if (myShape is Arc)
{
Arc myArc = (Arc)myShape; //downcast
myArc.start = 90;
myArc.sweep = 180;
}
}
if (myShape is Square)
{
Square mySquare = (Square)myShape; //downcast
mySquare.width = 20;
mySquare.height = 40;
}
But somehow this does not seem more efficient, in a way it is more
complex and harder to maintain.
The problem comes from the need to downcast the shape object into its
concrete class. If there were not strong typing I could just assign the
value (with the danger of a runtime crash if its the wrong type of
object.)
The above example demonstrates my problem, but in the actual code its
even worse, because in the above example I'm assigning values in place,
in the real code I grab an xml values, say radius, and set it to the
shape object as part of a case statement like this:
//what I would like to do...
switch (attribulename)
{
case "radius':
myshape.radius = attributevalue;
...more case statements
}
//what i am forced to do...
switch (attribulename)
{
case "radius':
if (myShape is Circle)
{
Circle myCicrle = (Circle)myShape;
myCircle.raduis = attributevalue;
}
if (myShape is Arc)
{
Arc myArc = (Arc)myShape;
myArc.raduis = attributevalue;
}
...more case statements
}
//the resultant code, with dozens of shapes, is atrocious.
One solution is to create one super class, that has all possible
attributes in it for every kind of shape, and then have a shapetype
property that tells me what kind of shape it really is. This seems to
destroy any benefit from subclassing altogether.
At this point, I'm wondering if there is any benefit to subclassing,
aside the "It's the proper thing to do" argument.
Open to any suggestions of ideas.
Thanks,
kpg
I'm having difficulty coming up with a design that I like for this
particular problem. He's the deal:
I have an abstract class and a set of concrete subclasses based on that
class, typical abstract class factory pattern. The abstract class is a
shape class, and the subclasses are types of shapes, circle, square,
arc, and so on.
I read an xml file which defines the shapes, it looks as expected:
<shapes>
<circle>
<x>0</x>
<y>0</y>
<radius>0</radius>
</circle>
... mode shapes here
</shapes>
So as I process the xml, I find out what kind of shape I need, I create
it and set the shape's properties based on the xml. The shape is then
added to a shape collection for later use.
Here is the class definition:
public abstract class Shape
{
public int x;
public int y;
}
public class Circle : Shape
{
public int radius;
}
public class Arc : Circle
{
public int start;
public int sweep;
}
public class Square : Shape
{
public int width;
public int height;
}
Now, I could have a case statement and do this:
//case need to build a circle
Circle myCircle = new Circle();
myCircle.x = 0;
myCircle.y = 0;
myCircle.radius = 15;
//case need to build an arc
Arc myArc = new Arc();
myArc.x = 0; //duplicate code
myArc.y = 0; //duplicate code
myArc.radius = 15; //duplicate code
myArc.start = 90;
myArc.sweep = 180;
//case need to build a Square
Square mySquare = new Square();
mySquare.x = 0; //duplicate code
mySquare.y = 0; //duplicate code
mySquare.width = 20;
mySquare.height = 40;
But this seems inefficient, all shapes have an x and y (at least) and
it needs to be set each time for each subclass.
So I could use a class factory and do this:
Shape myShape;
myShape = ShapeFactory(); //assume this retunrs the appropriate class
myShape.x = 0;
myShape.y = 0;
if (myShape is Circle)
{
Circle myCircle = (Circle)myShape; //downcast
myCircle.radius = 15;
if (myShape is Arc)
{
Arc myArc = (Arc)myShape; //downcast
myArc.start = 90;
myArc.sweep = 180;
}
}
if (myShape is Square)
{
Square mySquare = (Square)myShape; //downcast
mySquare.width = 20;
mySquare.height = 40;
}
But somehow this does not seem more efficient, in a way it is more
complex and harder to maintain.
The problem comes from the need to downcast the shape object into its
concrete class. If there were not strong typing I could just assign the
value (with the danger of a runtime crash if its the wrong type of
object.)
The above example demonstrates my problem, but in the actual code its
even worse, because in the above example I'm assigning values in place,
in the real code I grab an xml values, say radius, and set it to the
shape object as part of a case statement like this:
//what I would like to do...
switch (attribulename)
{
case "radius':
myshape.radius = attributevalue;
...more case statements
}
//what i am forced to do...
switch (attribulename)
{
case "radius':
if (myShape is Circle)
{
Circle myCicrle = (Circle)myShape;
myCircle.raduis = attributevalue;
}
if (myShape is Arc)
{
Arc myArc = (Arc)myShape;
myArc.raduis = attributevalue;
}
...more case statements
}
//the resultant code, with dozens of shapes, is atrocious.
One solution is to create one super class, that has all possible
attributes in it for every kind of shape, and then have a shapetype
property that tells me what kind of shape it really is. This seems to
destroy any benefit from subclassing altogether.
At this point, I'm wondering if there is any benefit to subclassing,
aside the "It's the proper thing to do" argument.
Open to any suggestions of ideas.
Thanks,
kpg