REWIND #2: Inheritance and Polymorphism

We reached another milestone!
In the past couple of weeks, we learnt all the core concepts underlying OOP!
This REWIND exercise will extend our previous one, using the latest OOP concepts we recently learnt!
Again, get creative and feel free to add more functionality to the system below!
Books ‘r’ Us has become Items ‘r’ Us!

Our previous BookSeller program has proven to be a hit with the book stores, and they now want to extend their range to include selling DVDs as well as books!
We will build on the OOP skills we developed in the BookSeller exercise, incorporating inheritance and polymorphism.
We are start with a simplified version of the BookSeller program, which only works with Books. We will extend it for Dvds.
Therefore, we are generalising our products as Items, therefore our BookSeller will become ItemSeller.
The required system functionality
We need to develop a system with the following functionality:
- Maintain the item seller’s cash balance.
- When the item seller purchases a new item:
- The cash balance is reduced (by the cost price).
- The item is added to the collection of items on offer.
- Give each item a unique ID.
- Determine the total number of items, of a certain type.
Example usage
This is how we might make use of our system:
public class Main {
public static void main(String[] args) {
ItemSeller shop = new ItemSeller("Items 'r' Us", 100.0);
System.out.println("Starting balance: $" + shop.getCashBalance());
System.out.println();
Book harryPotter = new Book("Harry Potter Philosopher Stone", "J. K. Rowling", 1997, 10.50, 29.95); // ID: 0
Dvd shawshank = new Dvd("The Shawshank Redemption", "Frank Darabont", 1994, 8, 22.95); // ID: 1
Item godFather = new Dvd("The Godfather", "Francis Ford Coppola", 1972, 11, 29.95); // ID: 2
// purchaseStock(Item) demonstrates polymorphism
shop.purchaseStock(harryPotter);
shop.purchaseStock(shawshank);
shop.purchaseStock(godFather);
System.out.println("Balance after purchasing stock: $" + shop.getCashBalance());
System.out.println("Total number of Items: " + shop.getTotalNumberOfItems());
System.out.println("Total number of DVDs: " + shop.getTotalNumberOfItems(Item.Type.DVD));
System.out.println("Total number of Books: " + shop.getTotalNumberOfItems(Item.Type.BOOK));
}
}
Let’s get busy!
You are provide with the following project:
Get your hands dirty!
Edit the above code:
- We start with a simple version of the
BookSellerandBookclasses from our previous REWIND exercise. To focus our attention on the inheritance and polymorphism aspects, we have removed some of the code we implemented last time. - Since the book seller will now be selling other items, we want to generalise it to
ItemSeller. RenameBookSellerasItemSellerin all the places (including the filenameBookSeller.java).- Hint: if you are using VS Code, you can right-click on the
BookSeller.javafile and select Rename. Or, simply pressF2when you select the file in the file explorer and type in the new name. If you get a message that tells you it wants to make refactoring changes, press the “OK” button (or press the “Show Preview” button if you want to see what changes will be made).
- Hint: if you are using VS Code, you can right-click on the
- Create an
Item.javafile and define theItemclass in it.- There are some
privateinstance fields inBookthat are general enough to also be used for DVDs (and other items). Move them intoItem, and remove them fromBook. Since we want them to be accessible to derived/children classes (i.e.BookandDvd), declare them asprotectedinItem. - There are also some
publicinstance methods inBookthat are general enough to be insideItem. Move them intoItem, and remove them fromBook. Keep these methodspublic. - Make the
Bookclass extend theItemclass. - Create a constructor for
Item, that sets the respective instance fields inItem(includingid). YourBookconstructor calls this constructor (usingsuper(...)) to set theIteminstance fields, and updates anyBook-only instance fields itself. - After all the changes above are made, the code should now compile and run again.
- The instance field
yearPublishedhas a poor name, since we don’t really say “published” for DVDs and other items. So, let us rename it (and the associated getter) to something more general -– likeyear(andgetYear()instead ofgetYearPublished()). Similarly,nextBookIDisn’t the best name. Change it tonextItemID. - So, what did you keep in the
Bookclass? Probably only theauthorinstance field, and thegetAuthor()instance method.
- There are some
- Refactor
ItemSellerto store and purchaseItems (not justBooks) in the appropriate places. Check that it all still compiles and runs. OverridethetoString()method inItem. It returns aStringcontaining theItem’s details as follows:"Item: <title> (<year>)". AlthoughBookdoesn’t override it yet, check that it works with aBookinstance.OverridethetoString()method inBook, which will overrideItem’s implementation oftoString()as"Book Item: <title> (<year>) <author>". Can you think of an elegant way to re-useItem’stoString()implementation from insideBook’stoString(), so that you don’t completely redo the common bits?- Define a
public enumcalledTypeinside theItemclass, withBOOKandDVDas possible values.- Declare a
public Item.Type getType()instance method inItem. - Define it in
Book, and implement it by returningType.BOOKas theType. - Does it make sense for
Itemto provide an implementation ofgetType()? Probably not, especially we want to avoid users creating instances ofItemdirectly (“item” is rather too general, somewhatabstract). So, makegetType()anabstractmethod, which of course also means makingItemnow becomes anabstract classalso.
- Declare a
- Create a
Dvdclass that extendsItem. Similar toBook, it:- Inherits some instance fields and methods from
Item, - Defines
getType()and@Overrides toString()declared inItem, and - Specialises by introducing a
String directorinstance field andpublic String getDirector()instance method.
- Inherits some instance fields and methods from
- Notice that the
public int getTotalNumberOfItems()method insideItemSellerdoes not tell us how many items of a particularType. Add another method:public int getTotalNumberOfItems(Item.Type type), such that it returns the number of items of the specified type. - Optional extensions: Add some of the other features from the last exercise into this program, for example:
- Selling items: at the
Itemlevel, - Searching by keyword: at the
Itemlevel, - Equality: at the
BookandDvdlevel.
- Selling items: at the
