9 Polymorphism

Polymorphism, Abstract Classes, and Interfaces

Objective

  • Declare and implement abstract classes and interfaces.
  • Apply composition, inheritance, and polymorphism.

Exercise 1*

  1. Implement all four classes represented in the hierarchy of the following class diagram.

    Shape+Shape()+area() : floatShape2D-width : float-height : float+Shape2D(float, float)+getWidth() : float+setWidth(float) : void+getHeight() : float+setHeight(float) : voidTriangle+Triangle(float, float)+area() : floatRectangle+Rectangle(float, float)+area() : float

A Triangle’s area is 0.5f * height * width and a Rectangle’s area is height * width. Note: Symbols rendered using italics are abstract.

  1. Add an interface Scalable with a scale(double) method and realize it using Triangle and Square.

    Scalable+scale(float) : voidTriangle+scale(float) : voidRectangle+scale(float) : void

Exercise 2*

Virtual Reserve

Create a virtual reserve with different types of animals, each with its unique behaviors.

  1. Use a base class Animal and derived classes like Lion, Bear, Gull, Duck, Crow, and Penguin. Each animal has a name and an age.
  2. Implement polymorphic methods such as eat(), move(), and sound() for each animal.
  3. Define interfaces for walking, flying, swimming, diving, and hibernating animals.
  4. Implement polymorphic methods such as walk(), fly(), swim(), dive(), and hibernate() based on the abilities of each animal.

Exercise 3

Create a project and implement the following class hierarchy:

PayableInvoiceEmployeeHourlyEmployeeSalariedEmployeeCommissionedEmployee Payable+getPaymentAmount() : double Invoice-partNumber : String-partDescription : String-quantity : int-unitPrice : double+Invoice(String, String, int, double)+getPaymentAmount() : double+toString() : String Employee-firstName : String-lastName : String-qid : String+Employee(String, String, String)+toString() : String HourlyEmployee-wage : double-hours : double+HourlyEmployee(String, String, String, double, double)+getPaymentAmount() : double+toString() : String SalariedEmployee-salary : double+SalariedEmployee(String, String, String, double)+getPaymentAmount() : double+toString() : String CommissionedEmployee-grossSales : double-commissionRate : double+CommissionedEmployee(String, String, String, double, double)+getPaymentAmount() : double+toString() : String

Test your implementation using the following main() method:

PayableTest.java
import java.util.ArrayList;
 
public class PayableTest {
  public static void main(String[] args) {
    // create payable list
    ArrayList<Payable> payables = new ArrayList<Payable>();
 
    // populate list with objects that implement Payable
    payables.add(new Invoice("01234", "Textbook", 2, 375.00));
    payables.add(new Invoice("56789", "USB Disk", 3, 179.95));
    payables.add(new SalariedEmployee("Ahmed", "Ali", "111-11-1111", 15000.00));
    payables.add(
        new HourlyEmployee("Fatima", "Saleh", "222-22-2222", 160.75, 40));
    payables.add(
        new CommissionedEmployee("Samir", "Sami", "333-33-3333", 100000, .06));
 
    System.out.println("Invoices and Employees processed polymorphically:\n");
    // generically process each element in array payableObjects
    for (Payable payable : payables) {
      // output currentPayable and its appropriate payment amount
      System.out.printf("ObjectType: %s - PaymentAmount = QR %.2f\n",
                        payable.getClass().getSimpleName(),
                        payable.getPaymentAmount());
      // if SalariedEmployee then increase the salary by 10%
      if (payable instanceof SalariedEmployee) {
        // downcast Payable reference to
        // SalariedEmployeeEmployee reference
        SalariedEmployee salariedEmployee = (SalariedEmployee)payable;
        double oldBaseSalary = salariedEmployee.getSalary();
        salariedEmployee.setSalary(oldBaseSalary * 1.1);
        System.out.printf("New salary with 10%% increase is: QR %,.2f\n",
                          salariedEmployee.getSalary());
      }
    }
  }
}

Exercise 4

Default / Static Interface Methods/Fields

Expert Cleaning Co. provides cleaning services to the residents of The Pearl, Qatar. You are tasked with building an application to allow them to manage the cleaning services provided and the fees to be collected from the residents.

The class diagrams of the application are shown in the figures below:

CleanableVehicleResidenceCarTruckUnitVillaResident Cleanable+fees : Map<String, Integer>+getFee(String) : int+setCleaningCount(int) : void+getCleaningAmount() : double Resident-id : int-name : String-vehicles : List<Vehicle>-residence : Residence+Resident()+Resident(int, String)+get*() :type+set*(type) : void+addVehicle(Vehicle) : void+deleteVehicle(String) : void+toString() : String Vehicle-plateNumber : String-wheels : int-weight : double-registrationDate : LocalDate-cleaningCount : int+Vehicle()+Vehicle(String, int, int, LocalDate)+get*() :type+set*(type) : void+toString() : String TransmissionType+AUTOMATIC+MANUALCar-passengers : int-transmission : TransmissionType+Car()+Car(String, int, int, LocalDate, int, TransmissionType)+get*() :type+set*(type) : void+toString() : String Truck-load : double+Truck()+Truck(String, int, int, LocalDate, double)+getWheelLoad() : double+toString() : String Residence-street : String-roomCount : int-cleaningCount : int+Residence()+Residence(String, int)+get*() :type+set*(type) : void+toString() String Unit-buildingName : String-unitNumber : int+Unit()+Unit(String, int, String, int)+get*() :type+set*(type) : void+toString() : String Villa-floorsCount : int+Villa()+Villa(String, int, int)+get*() :type+set*(type) : void+toString() : String

You are required to modify the Vehicle, Car, Truck, and Resident classes to complete the implementation of the above inheritance hierarchy. Create the TransmissionType as an enumeration and import java.time.LocalDate. The methods’ descriptions are as follow:

  1. Cleanable interface:

    • Use the following Map values for fees: Map.of("Car", 10, "Truck", 15, "Unit", 25, "Villa", 50 );
  2. Vehicle class:

    • Implements the Cleanable interface.

    • Modify the parameterized constructor so that it takes five arguments; add plateNumber, cleaningCount, and registrationDate.

    • Add the setters and getters for the new fields.

    • Implement the interface methods:

      • The setCleaningCount(int) is just a setter.

      • The getFee(String) returns the fee from the map using the provided string.

      • The getCleaningAmount() returns the product of the cleaningCount by the cleaning fee of the class type.

        Hint: call the getFee(String) method of the interface.

    • Modify the toString() method so that it includes plateNumber and registrationDate but only if the plateNumber value is not null, otherwise return "".

  3. Car class:

    • Modify the parameterized constructor to take the six arguments; see the class diagram.
  4. Truck class:

    • Modify the parameterized constructor to take the six arguments; see the class diagram.
  5. Residence class:

    • Implement the class as shown in the class diagram. This class implements Cleanable.
    • Implement the interface methods in a similar fashion to what you did in class Vehicle.
    • Override the toString() method to return a formatted string representation of the Residence instance.
  6. Unit class:

    • Implement the class as shown in the class diagram. This class extends Residence.
    • Override the toString() method to return a formatted string representation of a Unit instance.
  7. Villa class:

    • Implement the class as shown in the class diagram. This class extends Residence.
    • Override the toString() method to return a formatted string representation of a Villa instance.
  8. Resident class:

    • Copy the Person class from Exercise 8.1 to Resident.

    • Add a residence field and generate its setter and getter.

    • Add a list of vehicles as a private field and create its getter method; a setter is not required as it is meaningless.

    • Add the following methods:

    • Add the addVehicle() method which adds a Vehicle parameter to the list of vehicles. It should check that the parameter value is not null and that it does not already exist in the list of vehicles.

    • Add the following methods:

      public Vehicle getVehicle(String plateNumber) {
        // searches for a vehicle with plateNumber and returns it or returns null if
        // not found.
      }
       
      public void deleteVehicle(String plateNumber) {
        // searches for a vehicle with plateNumber and deletes it if found.
      }

Create a CleaningCoApp class with a main() method to test the application:

  1. Create a list of residents to store all the residents using the services of Expert Cleaning Co.

  2. Based on the example data provided below, create instances of Resident, and add them to the list of residents. Each resident lives in a Unit or a Villa and has a couple of Vehicles.

    John Doe lives in a Villa @ 55 La Plage Villas, The Pearl, Doha. The villa has 6 rooms and 2 floors. He requests cleaning his villa 4 times a month. He has the following cars:

    Plate NumberWheelsWeightPassengersTransmissionRegistration DateCleaning Count
    120141,9505Automatic2022-03-225

    He owns the following trucks:

    Plate NumberWheelsWeightLoadRegistration DateCleaning Count
    4211124,00012,0002023-07-015
    8003103,0008,0002015-08-241
    8025124,50015,0002019-02-212

    Jane Doe lives in a Unit @ 508 West Porto Drive, The Pearl, Doha. The Unit number is 16 at Porto Arabia building. The unit has 2 rooms. She requests cleaning her unit 3 times a month. She has the following cars:

    Plate NumberWheelsWeightPassengersTransmissionRegistration DateCleaning Count
    490741,9505Automatic2022-03-185
    909343,0008Manual2018-12-011
  3. Loop through the list of residents and display for each resident:

    • Resident name and address,
    • residence type,
    • the number of vehicles, and
    • the cleaning fees to be paid.

Exercise 5

Dates using LocalDate

  1. Create a class Person and an enumeration Gender using the following code:

    Person.java
    import java.time.LocalDate;
     
    public class Person {
      private String name;
      private LocalDate birthDate;
      private Gender gender;
     
      public Person() {}
      public Person(String name, LocalDate birthDate, Gender gender) {
        this.name = name;
        this.birthDate = birthDate;
        this.gender = gender;
      }
     
      public String getName() { return name; }
      public void setName(String name) { this.name = name; }
     
      public LocalDate getBirthDate() { return birthDate; }
      public void setBirthDate(LocalDate birthDate) { this.birthDate = birthDate; }
     
      public Gender getGender() { return gender; }
      public void setGender(Gender gender) { this.gender = gender; }
    }
    Gender.java
    public enum Gender {
      MALE,
      FEMALE;
    }
  2. Create a class PersonTest using the following code:

    PersonTest.java
    import java.time.LocalDate;
     
    public class PersonTest {
      public static void main(String[] args) {
        LocalDate date = LocalDate.of(1994, 9, 15);
        Person p1 = new Person("Jane", date, Gender.FEMALE);
        Person p2 = new Person("John", LocalDate.of(1995, 11, 20), Gender.MALE);
     
        if (p1.getBirthDate().isBefore(p2.getBirthDate()))
          System.out.println("P1 is older than P2");
        else
          System.out.println("P2 is older than P1");
      }
    }

Exercise 6+

Vehicle Hierarchy

Consider a hierarchy of vehicles with a base class Vehicle and derived classes like Car, Bicycle, and Boat. Each vehicle can have a move() method, and each derived class can implement it differently, simulating how different types of vehicles move.

Game Characters

Design a simple video game with characters like warriors, mages, and archers. Create a base class Character and subclasses for each character type. Implement polymorphic methods like attack(), defend(), and specialAbility() for each character.

Library System

Design a library management system with a base class LibraryItem and derived classes like Book, DVD, and Magazine. Each item type can have its own implementation of methods like checkOut() and returnItem(). Use polymorphism to handle different library items within the same system.

Vehicle Fleet

Create a program to manage a fleet of vehicles, including cars, trucks, and motorcycles. Define a base class Vehicle and subclasses for each vehicle type. Use polymorphism to handle common operations like start(), stop(), and fuelUp(). How would update your class hierarchy to account for electric vehicles?

Banking Transactions

Create a banking system with a base class Account and derived classes like SavingsAccount, CheckingAccount, and LoanAccount. Each account type can implement methods for depositing, withdrawing, and checking balances.

Payment Methods

Create a payment processing system with a base class PaymentMethod and derived classes like CreditCard, PayPal, and BankTransfer. Each payment method can have its own implementation for processing payments.

Online Shopping Cart

Develop an online shopping cart system with a base class Product and derived classes for product categories like Electronics, Clothing, and Books. Each product type can have its own pricing and shipping logic, making use of polymorphism to manage the cart.