Case Study Revisited
Let’s see how abstract classes can improve the picture drawing application that we examined in the earlier case study.
Version 2 of the application has a Shape class that looks like this:
open class Shape(val x: Int, val y: Int, val col: Color) {
open fun draw(context: Graphics2D) {
// nothing to do here
}
}
Just so you are clear on why this implementation is not ideal, return to
task15_4_2 in your repository and try the following:
-
Edit
Main.ktand add a new line to the code that configures thePictureobject:add(Shape(0, 0, Color.RED)) -
Rebuild and rerun the application with
./amper runThis should compile and run successfully, displaying the same picture as before.
This experiment demonstrates that adding actual Shape objects to a picture
is permitted, even though it is meaningless to do so!
Whilst this causes no real problems at run time, it would be nice if we could prevent meaningless code like this from compiling in the first place.
The solution is to make the Shape class abstract:
classDiagram
Shape <|-- Circle
Shape <|-- Rectangle
Picture o-- "0..*" Shape
class Shape {
<<abstract>>
x: Int
y: Int
col: Color
draw(context: Graphics2D)*
}
class Circle {
radius: Int
draw(context: Graphics2D)
}
class Rectangle {
width: Int
height: Int
draw(context: Graphics2D)
}
class Picture {
add(shape: Shape)
draw(context: Graphics2D)
}
The implementation of Shape now looks like this:
abstract class Shape(val x: Int, val y: Int, val col: Color) {
abstract fun draw(context: Graphics2D)
}
Task 16.3
-
The subdirectory
tasks/task16_3is an Amper project containing Version 3 of the picture drawing application, in whichShapeis now an abstract class.If you examine
Shape.kt, you’ll see the implementation shown above. -
Build and run the application with
./amper runYou should see a now-familiar picture appear.
-
Edit
Main.ktand add a new line to the code that configures thePictureobject:add(Shape(0, 0, Color.RED))This time, you should get a compiler error when you attempt to rebuild the application.