# Student, Instructor, Classroom * **Purpose** - to demonstrate the use of [Java interfaces](http://tutorials.jenkov.com/java/interfaces.html#java-interface-example) * **Objective** - to implement a `ZipCodeWilmington` _singleton_ which _mediates_ a _composite_ `Students` and `Instructors` reference. ### Part 1.1 - Create `Person` Class * Create a `Person` class. * The class should declare a `final` field named `id` of type `long`. * `Person` constructor should have a parameter of type `long` which sets the `id` field to the respective value. * The class should define a `getId()` method which returns the `Person` object's `id` field. * The class should define a `getName()` method which returns the `Person` object's `name` field. * The class should define a `setName()` method which sets the `Person` object's `name` field. - ### Part 1.0 - Test `Person` * Create a `TestPerson` class. * Create a `testConstructor` method which ensures that a `Person` object's `id` field is being set upon construction. * Create a `testSetName` method which ensures that a `Person` object's `name` variable is being set by invoking the `.setName` method. * Create a `testConstructor` method which ensures that a `Person` object's `name` variable is being set by invoking the `Person` constructor. - ### Part 2.0 - Create `Learner` Interface * Create a `Learner` interface. * `Learner` should declare one method signature: * Method name: `learn` * Method parameters: `double numberOfHours` * Method return-type: `void` - ### Part 3.1 - Create `Student` Class * Create a `Student` class such that: * `Student` is a subclass of `Person` * `Student` implements the `Learner` interface * `Student` should have an instance variable `totalStudyTime` of type `double` * `Student` should have a concrete implementation of the `learn` method which increments the `totalStudyTime` variable by the specified `numberOfHours` argument. * `Student` should have a `getTotalStudyTime()` method which returns the `totalStudyTime` instance variable. - ### Part 3.0 - Test `Student` * Create a `TestStudent` class. * Create a `testImplementation` method that asserts that a `Student` is an `instanceof` a `Learner`. * Create a `testInheritance` method that asserts that a `Student` is an `instanceof` a `Person`. * Create a `testLearn` method that ensures a `Student`'s `totalStudyTime` instance variable is incremented by the specified `numberOfHours` by invoking the `.learn` method. - ### Part 4.0 - Create `Teacher` Interface * Create a `Teacher` interface. * `Teacher` should declare a `teach` method signature: * Method name: `teach` * Method parameters: * `Learner learner` * `double numberOfHours` * Method return-type: `void` * `Teacher` should declare a `lecture` method signature: * Method name: `lecture` * Method parameters: * `Learner[] learners` * `double numberOfHours` * Method return-type: `void` - ### Part 5.1 - Create `Instructor` Class * Create an `Instructor` class such that: * `Instructor` is a subclass of `Person` * `Instructor` implements the `Teacher` interface * `Instructor` should have a concrete implementation of the `teach` method which invokes the `learn` method on the specified `Learner` object. * `Instructor` should have a concrete implementation of the `lecture` method which invokes the `learn` method on each of the elements in the specified array of `Learner` objects. * `numberOfHours` should be evenly split amongst the learners. * `double numberOfHoursPerLearner = numberOfHours / learners.length;` - ### Part 5.0 - Test `Instructor` * Create a `TestInstructor` class. * Create a `testImplementation` method that asserts that an `Instructor` is an `instanceof` a `Teacher`. * Create a `testInheritance` method that asserts that a `Instructor` is an `instanceof` a `Person`. * Create a `testTeach` method that ensures when an `Instructor` invokes the `.teach` method, a respective student's `totalStudyTime` instance variable is incremented. * Create a `testLecture` method that ensures when an `Instructor` invokes the `.teach` method, a respective student's `totalStudyTime` instance variable is incremented by the specified `numberOfHours`. - ### Part 6.1 - Create `People` class * Create a `People` class. * The class should instantiate an `ArrayList` field of `Person` objects named `personList`. * The class should define a method named `add` which adds a `Person` to the `personList`. * The class should define a method named `findById` which makes use of a `long id` parameter to return a `Person` object with the respective `id` field. * The class should define a method named `remove` which makes use of a `Person person` parameter to remove a respective `Person` object. * The class should define a method named `remove` which makes use of a `long id` parameter to remove a `Person` object with the respective `id` field. * The class should define a method named `getCount` which returns the size of `personList`. * The class should define a method named `getArray` which returns an array representation of the `personList` field. * The class should define a named `removeAll` which clears our `personList` field. - ### Part 6.0 - Test `People` * Create a `TestPeople` class. * Create a `testAdd` method which ensures that our `personList` in our `People` class populated with respective `Person` objects following invokation of the `add` method. * Create a `testRemove` method which ensures that the `personList` in a `People` object is **depopulated** with a respective `Person` object following the invokation of the `remove` method. * Create a `testFindById` method which ensures that a respective `Person` object with a respective `id` field is returned upon invokation of the `findById` method on a respective `People` object. - ### Part 7.1 - Create `Students` singleton * **Note:** The creation of this class will demonstrate an implementation of [singleton design pattern](https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples#eager-initialization). * Create a `Students` class. * The class should be an _unextendable_ subclass of the `People` class. * The class should _statically instantiate_ a `final` field named `INSTANCE` of type `Students`. * The class should define a _private nullary constructor_ which populates the `INSTANCE` field with respective `Student` representations of your colleagues. * Each student should have a _relatively_ unique `id` field. * The class should define a `getInstance` method which returns the `INSTANCE` field. - ### Part 7.0 - Test `Students` singleton * Create a `TestStudents` class. * Create a `test` method which ensures that each of the students in your current cohort are in your `Students` singleton. - ### Part 8.0 - Create and Test `Instructors` singleton * Use `Part 7` as a reference. * Create a `Instructors` singleton which represents the set of instructors at ZipCodeWilmington. * Create a `TestInstructors` class. - ### Part 9.1 - Create `ZipCodeWilmington` Class * Use `Part 7` as a reference. * Create a `ZipCodeWilmington` singleton. * The class should declare a field that references the instance of `Students` called `students`. * The class should declare a field that references the instance of `Instructors` called `instructors`. * The class should define a method `hostLecture` which makes use of a `Teacher teacher, double numberOfHours` parameter to host a `lecture` to the composite `people` field in the `students` reference. * The class should define a method `hostLecture` which makes use of a `long id, double numberOfHours` parameter to identify a respective `Instructor` to host a `lecture` to the composite `people` field in the `cohort` reference. - ### Part 9.0 - Test `ZipCodeWilmington` * Create a `TestZipCodeWilmington` class. * Create a `testHostLecture` method which ensures that each of the `Student`'s `totalStudyTime` instance variable is incremented by the specified `numberOfHours` upon invoking the `hostLecture` method. - # Notice the Design Flaw - Odd Casting Issues * You may have noticed that the `findById`, and `hostLecture` methods require an intermediate [casting trick](https://stackoverflow.com/questions/5289393/casting-variables-in-java). * To remedy this issue, we can _generify_ the `People` class. - ### Part 10.1 - Modify `People` class * [Parameterize](https://stackoverflow.com/questions/12551674/what-is-meant-by-parameterized-type) the `People` signature to enforce that it is a container for objects of type `E` such that `E` is a subclass of `Person`. * Modify the class signature to declare this class _abstract_. * An [abstract class](http://www.javacoffeebreak.com/faq/faq0084.html) cannot be instantiated; Its concrete implementation is deferred to its subclass. * Modify `people` field to enforce that is a container of objects of type `E`. * Modify the `add` method to ensure that it handles object of type `E`. * Modify the `findById` method to ensure that it returns an object of type `E`. * Modify the `getArray` method signature by declaring it `abstract` of return tyoe `E`. * An abstract method is a subclass's contractual agreement to the deferment of an implementation of a respective method. - ### Part 10.2 - Modify `People` subclasses * Modify the `Students` class signature to ensure that it is a subclass of `People` of parameterized type `Student`. * Modify the `Instructors` class signature to ensure that it is a subclass of `People` of parameterized type `Instructor`. * Provide concrete implementations of the `getArray` method in each of these classes. - ### Part 10.3 - Refactor `ZipCodeWilmington` class * Refactor the `hostLecture` method in the `ZipCodeWilmington` class by removing any intermediate _casting trick(s)_. - ### Part 10.0 - Test refactored classes. * Ensure that the `TestStudents`, `TestInstructors`, `TestPeople`, `TestZipCodeWilmington` classes were not affected by the refactor. - # Notice the Design Flaw - Non-Intuitive Orientation * You may have notice that `findById` makes it difficult to intuitively identify _which_ `Person` object is being returned.
Additionally, it's challenging to ensure **every** `Person` instance has a unique ID amongst its respective `People` subclass.
To remedy this issue, we redesign and refactor. - ### Part 11.1 - Create `Educator` enum * Create an enum named `Educator`. * The enum should implement `Teacher`. * The enum should have an enumeration for each of the instructors represented in the `Instructors` class. * Upon construction each enumeration of the enum should instantiate a respective `Instructor` and assign it to a final `instructor` field upon construction. The `instructor` should be added to the `Instructors` singleton. * Calls to the `teach` and `lecture` method should be differed to the composite `instructor` reference. * The enum should have a `double timeWorked` field which keeps track of the hours that the `Educator` has taught. - ### Part 11.0 - Test `Educator` * Use `Part 5` as a reference. - ### Part 12.1 - Test `ZipCodeWilmington` * Ensure the `hostLecture` method can handle objects of type `Educator`.