94. The Shapes demo - Interfaces
One interface is defined within the shapes library: TwoDimensionalShape:
TwoDimensionalShape interfacepackage org.groovy_tutorial.shapes
/**
* An interface for basic two-dimensional objects
*
* @see <a href="https://en.wikipedia.org/wiki/List_of_two-dimensional_geometric\
_shapes">
* Wikipedia: List of two-dimensional geometric shapes</a>
*
* @author Duncan Dickinson
*/
interface TwoDimensionalShape {
/**
* The length of the path surrounding a 2D shape
* @see <a href="https://en.wikipedia.org/wiki/Perimeter">Wikipedia: Perimet\
er</a>
* @return the perimeter of the shape
*/
BigDecimal getPerimeter()
/**
* The extent of a 2D shape in a plane
* @see <a href="https://en.wikipedia.org/wiki/Area">Wikipedia: Area</a>
* @return the area of the shape
*/
BigDecimal getArea()
/**
* A handy display string
* @return a text representation of the shape
*/
String getDisplayInfo()
/**
* @return the name of the shape
*/
String getShapeName()
}
The interface is declared using the interface keyword followed by the name: interface TwoDimensionalShape.
Within the interface is the following method signatures:
-
BigDecimal getPerimeter(): will return the shape’s perimeter -
BigDecimal getArea(): will return the shape’s area -
String getDisplayInfo(): is used to prepare a handy description of the shape -
String getShapeName(): returns the name of the shape (e.g. square or circle)
Each method signature is listed without a definition block ({...}) and it is up to the implementing class(es) to provide the “body” of the definition. The Circle class does just that:
Circle classpackage org.groovy_tutorial.shapes
import static java.lang.Math.PI
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
/**
* Describes a circle
* @author Duncan Dickinson
*/
@EqualsAndHashCode(includes = 'radius')
@ToString(includeNames = true, includeFields = true, includePackage = true)
final class Circle implements TwoDimensionalShape {
private static final String SHAPE_NAME = 'Circle'
/** The radius of the circle */
final BigDecimal radius
/** The circle's perimeter (circumference) */
final BigDecimal perimeter
/** The circle's area */
final BigDecimal area
/**
*
* @param radius the radius of the circle (must be a positive number)
* @throws IllegalArgumentException if radius <= 0
*/
Circle(BigDecimal radius) throws IllegalArgumentException {
ShapeUtil.checkSidesException(radius)
this.radius = radius
this.perimeter = calculatePerimeter(radius)
this.area = calculateArea(radius)
}
/**
* Helper function - defers to calculatePerimeter
* @see #calculatePerimeter(Number)
* @param radius
* @return the circumference (perimeter)
* @throws IllegalArgumentException if radius <= 0
*/
static BigDecimal calculateCircumference(Number radius) throws IllegalArgume\
ntException {
calculatePerimeter(radius)
}
/**
* Calculates the perimeter of a circle using the formula: p = 2*Pi*r
* @param radius
* @return the perimeter
* @throws IllegalArgumentException if radius <= 0
*/
static BigDecimal calculatePerimeter(Number radius) throws IllegalArgumentEx\
ception {
ShapeUtil.checkSidesException(radius)
(2 * PI * radius) as BigDecimal
}
/**
* Calculates the area of a circle using the formula: a = Pi*r^2
* @param radius
* @return the area
* @throws IllegalArgumentException if radius <= 0
*/
static BigDecimal calculateArea(Number radius) throws IllegalArgumentExcepti\
on {
ShapeUtil.checkSidesException(radius)
(PI * radius**2) as BigDecimal
}
/**
* Calculates the circle's diameter using the formula: d = 2r
* @param radius
* @return the diameter
* @throws IllegalArgumentException if radius <= 0
*/
static BigDecimal calculateDiameter(Number radius) throws IllegalArgumentExc\
eption {
ShapeUtil.checkSidesException(radius)
(radius * 2) as BigDecimal
}
@Override
String getDisplayInfo() {
"$SHAPE_NAME: radius = $radius; diameter = $diameter; \
circumference = ${circumference}; area = ${area}"
}
/**
* Just a convenience - equivalent to getPerimeter
* @return the circumference
*/
BigDecimal getCircumference() {
perimeter
}
/**
* A pseudo getter
* @return the diameter
*/
Number getDiameter() {
calculateDiameter(this.radius)
}
@Override
String getShapeName() {
SHAPE_NAME
}
}
You’ll notice that the Circle class doesn’t explicitly provide an implementation for getPerimeter() and
getArea() as Groovy will generate these for the member fields.