Lab: 12 - Polymorphism and Interfaces

Assigned
Wednesday, 20 September 2023

OVERVIEW In today’s lab, we will create abstracts classes, and multiple classes (and objects) that implement the same interface.

An Abstract Method

For this exercise, we will continue working with the CounterWithMemory you created in Lab 11: Inheritance. Another potentially useful method returns a String representation of the current tally. We can imagine that, for some applications (such as logging the counts over a long period of time), we might want the String representation to include with the tally count the name of the counter and a time stamp that records current date and time, while in other cases we just want just the base-ten numeral corresponding to the current tally.

One way to arrange this is to add an abstract method to the CounterWithMemory class and then to derive two (or possibly more) classes from it, containing different implementations of the abstract method.

  • Add abstract method show to the definition of the CounterWithMemory class. This method takes no arguments and returns a String. To do this, you must change the CounterWithMemory class to be an abstract class.

  • Define two new derived classes: BasicCounterWithMemory and LoggingCounterWithMemory. One key difference between them will be how they implement the show method. The BasicCounterWithMemory class show method returns just the base-ten numeral for the current tally. The LoggingCounterWithMemory should create a show method that returns a String that also contains the counter’s name and a time stamp. (You can get the current date and time by importing the java.util.Date class and calling its zero-argument constructor. Objects of this class have a toString method that return time stamps accurate to the second.)

Note that BasicCounterWithMemory and LoggingCounterWithMemory classes need to have a one-argument constructor. What is the argument of these constructors?

  • (1/2 point) Write a set of JUnit test methods that test your new method and subclasses.
  • (1/2 point) Create the UML diagram that represents the Counters hierarchy.

Research about regular expressions (Optional - extra 2 points)

Polymorphism and Interfaces (3 points)

This interface — call it Responder — consists of a single abstract method, respond, which takes one argument, a String, and returns a String. The idea is that a Responder can, in effect, hold up one end of a conversation, speaking whenever it is spoken to; the String that the respond method returns is the object’s reply to the String that that method receives as argument.

Create the Responder Interface

  1. In Eclipse, start a new project called conversation, and in that project create the Responder interface.

  2. Write an opening comment to introduce the Responder interface, then write the Java code to define that interface.

Echoes

An Echo is an object that implements the Responder interface with a respond method that always returns the same String that it receives.

  1. Document and write a definition for the Echo class.

  2. Start a JUnit test class ResponderTester, to test the various kinds of Responders that you will define in this lab.

  3. Write tests for the Echo class and then compile and run ResponderTester and confirm that your implementation of the Echo class passes the test.

Bores

A Bore is an object that implements the Responder interface with a respond method that ignores the String it receives and always replies with the same fixed String. The Bore class has a one-argument constructor through which the programmer specifies its constant response.

  • Document, write, and test a definition for the Bore class.

Disemvowelers

A Disemvoweler is an object that implements the Responder interface with a respond method that removes all the vowels from the String it receives and returns the result. (Comment moderators in social networks sometimes apply the disemvoweling operation to comments contributed by trolls, so to express a degree of disapprobation without complete censorship.)

  • Document, write, and test a definition for the Disemvoweler class. To implement the respond method, you may use replaceAll method of String class. This method takes two String parameters. It replaces all occurances of the first parameter with the second parameter. (Read the documentation)

Recapitulators

A Recapitulator is an object that implements the Responder interface with a respond method that replies with the null String the first time it is invoked, and replies to any subsequent invocation with the concatenation of all the strings that it has previously received as arguments, each terminated with a newline character.

Suppose obj is an object reference for Recapitulator. Here are the expected outputs after each call to respond method:

System.out.println(obj.respond("hello")); // null
System.out.println(obj.respond("world")); // hello
System.out.println(obj.respond("!"));  /* hello 
                                          world  */
  • Document, write, and test a definition for the Recapitulator class.

Numberers

A Numberer is an object that implements the Responder interface by tweaking the operation of another Responder object, numerand. When a Numberer receives the respond message, it takes the argument and sends numerand a respond message with the same argument. Numberer then receives numerand’s reply, prepends a serial number to it (“1:” on the first invocation, “2:” on the second, and so on), and returns the result. Use the String.format method to create the reply/response from Numberer.

Here’s an example of the kind of exchange that takes place when numerand is a Disemvoweler:

  - if you call numberer.respond( "Hello!" ) the result is `1:Hll!`     
  - then if you call numberer.respond("Is anyone there?") the result is `2:s nyn thr?`
  • Document, write, and test a definition for the Numberer class. In this case, “test” means to write a program that calls the methods in your Numberer class. Note that the constructor needs another Responder as its argument. Use the format method from the String class to display the reply from Numberer.

Composers

A Composer is an object that implements the Responder interface by combining the operations of two other Responder objects—let’s call them fore and aft. When a Composer receives the respond message, it takes the argument and sends fore a respond message with that argument. When fore replies, the Composer sends aft a respond message with that reply as its argument. The Composer returns aft’s reply as its own response to the respond message it received.

If, for instance, fore is a Bore that replies to any conversational opening with the response “Hi, I’m having fun learning Java!”, and aft is a Disemvoweler, then the Composer would respond to the string “Hello – pleased to meet you.” with the string “H, ‘m hvng fn lrnng Jv!”.

The Composer class needs a two-argument constructor through which the programmer can specify fore and aft.

Document, write, and test a definition for the Composer class.

Lab Submission

You will submit your files via Gradescope by the end of the week.

  • The code for CounterWithMemory, BasicCounterWithMemory and LoggingCounterWithMemory classes, the JUnit Test case, the UML diagram, and a screenshoot of the JUnit test output (JUnit view).
  • All the classes, interfaces and JUnit case test related to the Polymorphism and Interfaces exercise. A screenshoot of the JUnit test output (JUnit view).

I strongly recommend that each student keep a copy of the lab. Therefore, don’t forget to share the files/folder with your lab partner!

Remember: Write your code anticipating errors and print user-friendly error messages, all your public methods should be well documented (use Javadoc comments). You should include comments or organize your code and lab report in a way that will help the grader to find the answer to the exercises or posted questions.