This is an assignment to the Software Architecture class at the Technische Hochschule Nürnberg.
Assignment 5: Generics and Bounds
This assignment covers an advanced topic of generics: bounds on type parameters and wildcards. Bounds describe type constraints of generic classes or methods that allow to balance type safety with flexibility of use.
Setup
- Create a fork of this repository (button in the right upper corner)
- Clone the project (get the link by clicking the green Clone or download button)
- Import the project to your IDE (remember the guide in assignment 1)
- Validate your environment by running the tests from your IntelliJ and by running
gradle test
on the command line.
Groundwork
First, create the model for this assigment:
- Create the
enum
PlantColor - Implement the
abstract
class Plant - Implement the child classes Flower and Shrub
Remarks:- A shrub is always green; a flower may be any color but green (handle a wrong value in the constructor)
- Flowers compare to each other by height
- All good data classes should always implement
equals
andhashCode
, ideally alsotoString
.
- Create tests to ensure that your model classes are correct (e.g. green flowers won't work)
Basic Bounds
Implement a PlantBed
which manages a list of plants (use SimpleList<T>
).
A PlantBed
may contain any subclass of Plant
but nothing else!
Use appropriate bounds when declaring the generic class.
Remarks: The method getPlantsByColor
is very easy to implement if you think of the filter
method of the SimpleList
!
Remember to create tests for nearly every line you code!
Bounds on Wildcards
Last but not least we'll look at the PECS (Producer Extends Consumer Super) principle.
- Modify the
map
method of theSimpleList
interface according to the PECS principle - Implement the utility method
splitBedByColor
in a utility classPlantBedUtility
. Why should this class be declaredabstract
and have aprivate
constructor?
Remark: the above UML diagram for the utility method does not include any bounds but you need some (PECS!) -- the compiler is unable to capture the types if you implement the method strictly as described in the UML!