Once you have a good idea about the methods common to each
type of shape, you can define the shape classes themselves. In terms
of how many methods you need to implement, the simplest shape is
the Circle class, shown here:
package com.example.programmingas3.geometricshapes
{
public class Circle implements IGeometricShape
{
public var diameter:Number;
public function Circle(diam:Number = 100):void
{
this.diameter = diam;
}
public function getArea():Number
{
// The formula is Pi * radius * radius.
var radius:Number = diameter / 2;
return Math.PI * radius * radius;
}
public function getCircumference():Number
{
// The formula is Pi * diameter.
return Math.PI * diameter;
}
public function describe():String
{
var desc:String = "This shape is a Circle.\n";
desc += "Its diameter is " + diameter + " pixels.\n";
desc += "Its area is " + getArea() + ".\n";
desc += "Its circumference is " + getCircumference() + ".\n";
return desc;
}
}
}
The Circle class implements the IGeometricShape interface, so
it must provide code for both the
getArea()
method
and the
describe()
method. In addition, it defines
the
getCircumference()
method, which is unique
to the Circle class. The Circle class also declares a property,
diameter
,
which won’t be found in the other polygon classes.
The other two types of shapes, squares and equilateral triangles,
have some other things in common: they each have sides of equal
length, and there are common formulas you can use to calculate the
perimeter and sum of interior angles for both. In fact, those common
formulas apply to any other regular polygons that you define in
the future as well.
The RegularPolygon class is the superclass for both the Square
class and the EquilateralTriangle class. A superclass lets you define
common methods in one place, so you don’t have to define them separately
in each subclass. Here is the code for the RegularPolygon class:
package com.example.programmingas3.geometricshapes
{
public class RegularPolygon implements IPolygon
{
public var numSides:int;
public var sideLength:Number;
public function RegularPolygon(len:Number = 100, sides:int = 3):void
{
this.sideLength = len;
this.numSides = sides;
}
public function getArea():Number
{
// This method should be overridden in subclasses.
return 0;
}
public function getPerimeter():Number
{
return sideLength * numSides;
}
public function getSumOfAngles():Number
{
if (numSides >= 3)
{
return ((numSides - 2) * 180);
}
else
{
return 0;
}
}
public function describe():String
{
var desc:String = "Each side is " + sideLength + " pixels long.\n";
desc += "Its area is " + getArea() + " pixels square.\n";
desc += "Its perimeter is " + getPerimeter() + " pixels long.\n";
desc += "The sum of all interior angles in this shape is " + getSumOfAngles() + " degrees.\n";
return desc;
}
}
}
First, the RegularPolygon class declares two properties that
are common to all regular polygons: the length of each side (the
sideLength
property)
and the number of sides (the
numSides
property).
The RegularPolygon class implements the IPolygon interface and
declares all four of the IPolygon interface methods. It implements
two of these—the
getPerimeter()
and
getSumOfAngles()
methods—using
common formulas.
Because the formula for the
getArea()
method
differs from shape to shape, the base class version of the method
cannot include common logic that can be inherited by the subclass
methods. Instead, it simply returns a 0 default value to indicate
that the area was not calculated. To calculate the area of each
shape correctly, the subclasses of the RegularPolygon class have
to override the
getArea()
method themselves.
The following code for the EquilateralTriangle class show how
the
getArea()
method is overridden:
package com.example.programmingas3.geometricshapes
{
public class EquilateralTriangle extends RegularPolygon
{
public function EquilateralTriangle(len:Number = 100):void
{
super(len, 3);
}
public override function getArea():Number
{
// The formula is ((sideLength squared) * (square root of 3)) / 4.
return ( (this.sideLength * this.sideLength) * Math.sqrt(3) ) / 4;
}
public override function describe():String
{
/* starts with the name of the shape, then delegates the rest
of the description work to the RegularPolygon superclass */
var desc:String = "This shape is an equilateral Triangle.\n";
desc += super.describe();
return desc;
}
}
}
The
override
keyword indicates that the
EquilateralTriangle.getArea()
method
intentionally overrides the
getArea()
method from
the RegularPolygon superclass. When the
EquilateralTriangle.getArea()
method
is called, it calculates the area using the formula in the preceding
code, and the code in the
RegularPolygon.getArea()
method
never executes.
In contrast, the EquilateralTriangle class doesn’t define its
own version of the
getPerimeter()
method. When
the
EquilateralTriangle.getPerimeter()
method is
called, the call goes up the inheritance chain and executes the
code in the
getPerimeter()
method of the RegularPolygon
superclass.
The
EquilateralTriangle()
constructor uses the
super()
statement
to explicitly invoke the
RegularPolygon()
constructor
of its superclass. If both constructors had the same set of parameters,
you could have omitted the
EquilateralTriangle()
constructor
completely, and the
RegularPolygon()
constructor
would be executed instead. However, the
RegularPolygon()
constructor
needs an extra parameter,
numSides
. So the
EquilateralTriangle()
constructor
calls
super(len, 3)
, which passes along the
len
input
parameter and the value 3 to indicate that the triangle has three
sides.
The
describe()
method also uses the
super()
statement,
but in a different way. It uses it to invoke the RegularPolygon
superclass’ version of the
describe()
method. The
EquilateralTriangle.describe()
method first
sets the
desc
string variable to a statement about
the type of shape. Then it gets the results of the
RegularPolygon.describe()
method
by calling
super.describe()
, and it appends that
result to the
desc
string.
The Square class isn’t described in detail here, but it is similar
to the EquilateralTriangle class, providing a constructor and its
own implementations of the
getArea()
and
describe()
methods.