7 Composition

Composition

Objective

  • Composition and its practical applications in software development.
  • Build a complete example using object-oriented programming with composition.

Exercise 1*

Customer Class

A class can have references to objects of other classes as members. This is called composition and is sometimes referred to as a has-a relationship. For example, a Customer object needs to record the Address of the client. The address is not a simple string, it is another object with many fields.

  1. Add the following Customer and Address classes to your project:

    Customer.java
    public class Customer {
      private String name;
      private String phone;
      private int id;
     
      public Customer(String name, String phone, int id) {
        this.name = name;
        this.phone = phone;
        this.id = id;
      }
     
      public String getName() { return name; }
      public String getPhone() { return phone; }
      public int getId() { return id; }
     
      public void setName(String name) { this.name = name; }
      public void setPhone(String phone) { this.phone = phone; }
      public void setId(int id) { this.id = id; }
     
      @Override
      public String toString() {
        return "Name: " + name + ", Phone: " + phone + ", ID: " + id;
      }
    }
    Address.java
    public class Address {
      private String street;
      private String city;
      private String state;
      private String zip;
     
      public Address(String street, String city, String state, String zip) {
        this.street = street;
        this.city = city;
        this.state = state;
        this.zip = zip;
      }
     
      public String getStreet() { return street; }
      public String getCity() { return city; }
      public String getState() { return state; }
      public String getZip() { return zip; }
     
      public void setStreet(String street) { this.street = street; }
      public void setCity(String city) { this.city = city; }
      public void setState(String state) { this.state = state; }
      public void setZip(String zip) { this.zip = zip; }
     
      @Override
      public String toString() {
        return street + ", " + city + ", " + state + " " + zip;
      }
    }
  2. Modify the class Customer by adding new data member called address of type Address.

  3. Add a fully parameterized constructor in the Customer class that initializes all fields including the address.

  4. Add a setter and a getter for the address data member.

    Customer-name : String-phone : String-id : int-address : Address+Customer(String, String, int)+Customer(String, String, int, Address)+getName() : String+getPhone() : String+getId() : int+getAddress() : Address+setName(String) : void+setPhone(String) : void+setId(int) : void+setAddress(Address) : void+toString() : StringAddress-street : String-city : String-state : String-zip : String+Address(String, String, String, String)+getStreet() : String+getCity() : String+getState() : String+getZip() : String+setStreet(String) : void+setCity(String) : void+setState(String) : void+setZip(String) : void+toString() : String
  1. Modify the toString() method by adding the Address.toString() to the returned string.
  2. Create two Customer objects and set their addresses.
  3. Test your code.

Exercise 2

Book Class

  1. Add the following Book and Author classes to your project:

    Book.java
    public class Book {
      private String isbn;
      private String title;
      private double price;
     
      public Book(String isbn, String title, double price) {
        this.isbn = isbn;
        this.title = title;
        this.price = price;
      }
      public String getIsbn() { return isbn; }
      public String getTitle() { return title; }
      public double getPrice() { return price; }
     
      public void setIsbn(String isbn) { this.isbn = isbn; }
      public void setTitle(String title) { this.title = title; }
      public void setPrice(double price) { this.price = price; }
     
      @Override
      public String toString() {
        return title + " [" + isbn + "]" + " $" + price;
      }
    }
    Author.java
    public class Author {
      private int id;
      private String firstName;
      private String lastName;
     
      public Author(int id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
      }
     
      public int getId() { return id; }
      public String getFirstName() { return firstName; }
      public String getLastName() { return lastName; }
     
      public void setId(int id) { this.id = id; }
      public void setFirstName(String firstName) { this.firstName = firstName; }
      public void setLastName(String lastName) { this.lastName = lastName; }
     
      @Override
      public String toString() {
        return lastName + ", " + firstName;
      }
    }
  2. Add an author with type Author as a new data member to the Book class.

  3. Add a new Book constructor.

  4. Add a getter and a setter for author.

    Book-isbn : String-title : String-price : double-author : Author+Book(String, String, double)+Book(String, String, double, Author)+getIsbn() : String+getTitle() : String+getPrice() : double+getAuthor() : Author+setIsbn(String) : void+setTitle(String) : void+setPrice(double) : void+setAuthor(Author) : void+toString() : StringAuthor-id : int-firstName : String-lastName : String+Author(int, String, String)+getId() : int+getFirstName() : String+getLastName() : String+setId(int) : void+setFirstName(String) : void+setLastName(String) : void+toString() : String
  1. Use Author’s toString() method in Book’s toString() method.

  2. Test your code.

  3. Add the following Publisher class to your project:

    Publisher.java
    public class Publisher {
      private int id;
      private String name;
      private String email;
     
      public Publisher(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
      }
     
      public int getId() { return id; }
      public String getName() { return name; }
      public String getEmail() { return email; }
     
      public void setId(int id) { this.id = id; }
      public void setName(String name) { this.name = name; }
      public void setEmail(String email) { this.email = email; }
     
      @Override
      public String toString() {
        return name + "<" + email + ">";
      }
    }
  4. Add an address with type Address as a new data member of the Publisher class.

  5. Add a new constructor to the Publisher class.

  6. Define a getter and a setter for address.

    Publisher-id : int-name : String-email : String-address : Address+Publisher(int, String, String)+Publisher(int, String, String, Address)+getId() : int+getName() : String+getEmail() : String+getAddress() : Address+setId(int) : void+setName(String) : void+setEmail(String) : void+setAddress(Address) : void+toString() : StringAddress
  7. Use Address’s toString() method in Publisher’s toString() method.

  8. Test your code.

  9. Update the Book class by adding a new data member publisher of type Publisher. Repeat all the steps that you did previously with the other classes.

    Book-author : Author-publisher : Publisher+Book(String, String, double, Author, Publisher)AuthorPublisher
  10. Test your code with proper data.

CustomerAddressBookAuthorPublisher

Exercise 3

A book generally contains multiple chapters. Each chapter has a name and number of pages. We will make this change to the Book class. This time we are not going to add Chapter as a data member but instead we will add an ArrayList of Chapter objects.

  1. Add the following Chapter class to your project:

    Chapter.java
    public class Chapter {
      private String title;
      private int pageCount;
     
      public Chapter(String title, int pageCount) {
        this.title = title;
        this.pageCount = pageCount;
      }
     
      public String getTitle() { return title; }
      public int getPageCount() { return pageCount; }
     
      public void setTitle(String title) { this.title = title; }
      public void setPageCount(int pageCount) { this.pageCount = pageCount; }
     
      @Override
      public String toString() {
        return title + " (" + pageCount + " pages)";
      }
    }
  2. Add an ArrayList of Chapters named chapters as a new data member. There is no need to create or modify the constructor.

  3. Add a setter and getter for chapters.

  4. Add two methods: void addChapter(Chapter c) and void removeChapter(Chapter c). The add() and remove() methods will make the changes directly to the list of chapters.

  5. Add a two methods: int getPageCount(), that returns the total number of pages in all the chapters, and int getChapterCount().

    Book-chapters : List<Chapter>+Book(String, String, double, Author, Publisher)+getChapters() : List<Chapter>+setChapters(List<Chapter>) : void+addChapter(Chapter) : void+removeChapter(Chapter) : void+getPageCount() : int+getChapterCount() : intChapter-title : String-pageCount : int+Chapter(String, int)+getTitle() : String+getPageCount() : String+setTitle(String) : void+setPageCount(int) : void+toString() : String
  6. Modify the toString() method of the Book class to display the number of chapters and the total number of pages.

  7. Test your code with proper data. Create a Book object that has two chapters, a publisher who has an address, and an author:

    Address address = new Address("501 Boylston St.", "Boston", "Massachusetts", "02116");
    Publisher publisher = new Publisher(1, "Addison-Wesley Professional", "[email protected]");
    Author author = new Author(1, "Donald", "Knuth");
    Chapter ch1 = new Chapter("Chapter 1: Basic concepts", 229);
    Chapter ch2 = new Chapter("Chapter 2: Information Structures", 234);
    Book book = new Book("978-0201896831", "The Art of Computer Programming, Vol. 1: Fundamental Algorithms", 62.49);

    Modify the code above and associated classes so that your output is as follows:

    The Art of Computer Programming, Vol. 1: Fundamental Algorithms by Knuth, Donald
    Publisher: Addison-Wesley Professional <[email protected]m>; 501 Boylston St., Boston, Massachusetts 02116
    2 chapters, 463 pages, $62.49, [978-0201896831]
  8. To support multiple authors for a single book, change the author data member to a List of Authors and update the constructor. You also need to add methods like int getAuthorCount(), void addAuthor(Author a), and void removeAuthor(Author a).

    Make sure you do not add duplicate authors for a single book by preventing an author ID from being added twice. Furthermore, you need to print the list of all authors in the toString() of the Book class.

    Book-author : List<Author>+Book(String, String, double, Publisher)+getAuthors() : List<Author>+setAuthors(List<Author>) : void+getAuthorCount() : int+addAuthor(Author) : void+removeAuthor(Author) : voidAuthor

Exercise 4+

Hotel Application

We are going to build a mini-hotel application. The hotel has a name, a location, and a list of rooms. Rooms can be booked and released. Three types of rooms available: single, double, and suite.

  1. Add the following Location class to your project:

    Location.java
    public class Location {
      private String city;
      private String country;
     
      public Location(String city, String country) {
        this.city = city;
        this.country = country;
      }
     
      public String getCity() { return city; }
      public String getCountry() { return country; }
     
      public void setCity(String city) { this.city = city; }
      public void setCountry(String country) { this.country = country; }
     
      @Override
      public String toString() {
        return city + ", " + country;
      }
    }
    Location-city : String-country : String+Location(String, String)+getCity() : String+getCountry() : String+setCity(String) : void+seCountry(String) : void+toString() : String
  2. Add the following Room class to your project:

    Room.java
    public class Room {
      private int number;
      private int floor;
      private boolean available;
     
      public Room(int number, int floor, boolean available) {
        this.number = number;
        this.floor = floor;
        this.available = available;
      }
     
      public int getNumber() { return number; }
      public int getFloor() { return floor; }
      public boolean isAvailable() { return available; }
     
      public void setNumber(int number) { this.number = number; }
      public void setFloor(int floor) { this.floor = floor; }
      public void setAvailable(boolean available) { this.available = available; }
     
      @Override
      public String toString() {
        return String.format("Room number: %d\tFloor: %d\tAvailable: %s", number,
                            floor, (this.isAvailable() ? "Yes" : "No"));
      }
    }
    Room-number : int-floor : int-available : boolean+Room(int, int, boolean)+getNumber() : int+getFloor() : int+isAvailable() : boolean+setNumber(int) : void+setFloor(int) : void+setAvailable(boolean) : void+toString() : String
  3. Create a RoomType enumeration with three values: SINGLE, DOUBLE, SUITE.

  4. Make roomType: RoomType a field of the Room class. Add it to the fully parameterized constructor.

  5. Add a setter and getter for the roomType data member.

  6. Modify the toString() method of the Room class based on the following example:

    Room room = new Room(425,4, true, RoomType.DOUBLE);
    System.out.println(room);
    [DOUBLE] Room number: 425     Floor: 4     Available: Yes

Composing Classes

The Hotel class has three fields: name, location, and rooms.

  1. Provide two constructors: one takes the name, and the other takes the name and location.

  2. Provide setters and getters for all three fields.

  3. Add three private constants to the Hotel class:

    private final double SINGLE_ROOM_RATE = 355.5;
    private final double DOUBLE_ROOM_RATE = 515.5;
    private final double SUITE_RATE = 1079.5;
  4. Provide all the following methods:

    • public double getRoomRate(RoomType type): returns the rate for a given room type.
    • public void addRoom(Room r): adds a new object to the hotel’s list of rooms.
    • public void reserveRoom(int roomNumber): sets the room availability to false.
    • public void releaseRoom(int roomNumber): sets the room availability to true.
    • public boolean isRoomAvailable(int roomNumber): returns room availability.
    • public ArrayList<Room> getAvailableRooms(): returns a list of the available rooms.
    • public int getAvailableRoomsCount(): returns the number of available rooms in the hotel’s list of rooms.
    • public int getRoomsCount(): returns the number of all hotel rooms.
    • public ArrayList<Room> roomsInFloor(int floorNumber): returns a list of the rooms in a specific floor number.
  5. Provide a toString() method that reuses code from all the included classes and generates a string based on the following output:

    Hotel: Hilton. Address: Doha, Qatar
    Room Count: 4 (Available: 3)
    Today's Income: $515.50
    [DOUBLE] Room number: 425     Floor: 4     Available: No  @   $515.50
    [SINGLE] Room number: 423     Floor: 4     Available: Yes @   $355.50
    [DOUBLE] Room number: 328     Floor: 3     Available: Yes @   $515.50
    [SUITE]  Room number: 218     Floor: 2     Available: Yes @ $1,079.50

Hotel Tester

  1. Test your classes using the following code:

    Hotel hotel = new Hotel("Hilton");
    Room room1 = new Room(425, 4, true, RoomType.DOUBLE);
    Room room2 = new Room(423, 4, true, RoomType.SINGLE);
    Room room3 = new Room(328, 3, true, RoomType.DOUBLE);
    Room room4 = new Room(218, 2, true, RoomType.SUITE);
     
    hotel.setLocation(new Location("Doha", "Qatar"));
    hotel.addRoom(room1);
    hotel.addRoom(room2);
    hotel.addRoom(room3);
    hotel.addRoom(room4);
    hotel.reserveRoom(425);
    hotel.reserveRoom(218);
     
    System.out.println(hotel);

Booking Application

  1. Create a class named BookingApplication.
  2. The BookingApplication class has two fields: a name and a list of hotels.
  3. Discuss the usage of this application:
    1. What can you do with it?
    2. How can you benefit from the available code?
    3. What changes are needed to make it a fully-fledged application?