5.1. Introduction

As you will see in this chapter, interfaces allow programmers to write code that works on various data types. Imagine you build a website that accepts payments from various payment processing services such as Visa and PayPal. After a few months, you want to start allowing payments from other payment processing services that aren’t currently supported (Affirm, for example).

Proper use of interfaces while designing/building your website would allow you to add more payment services without requiring you to code significant updates to the underlying site. In other words, the work required to support more services would be minimized!

As long as we can guarantee that all of the payment processing services have a certain set of behaviors (methods), the program that uses these behaviors (our website) does not have to change in order to work correctly with all of the services (even new ones)!

In this chapter, we will show how this would work with the payment processor example and then we will provide you with a hands-on example that allows you to style output in various ways without changing the driver program.

Thought Exercise

To demonstrate the benefits of interfaces, we will use a short UGABookstore class with methods allowing customers to purchase items in different ways (with Visa or PayPal). The code below shows how you might write the code to process payments with Visa and PayPal. (Of course, in reality, the code inside of each method would be much larger and more complex).

You can safely assume that the UGABookstore class has access to the Visa and Paypal classes and that any methods called exist in those classes (even though we haven’t seen the code yet).

Listing 5.1 UGA Bookstore Class
public class UGABookstore {

   public boolean purchase(Visa visa, String customerName, double amount) {
       visa.processPayment(amount);
       visa.printReceipt(customerName, amount);
   } // purchase

   public boolean purchase(PayPal paypal, String customerName, double amount) {
       paypal.processPayment(amount);
       paypal.printReceipt(customerName, amount);
   } // purchase

   public static void main(String[] args) {
      // This method is the main entry point of the application and
      // contains calls to the purchase method. Specific code is omitted.

   } // main
} // UGABookstore

Take a moment to look closely at both purchase methods (method overloading). The only difference between them is the first parameter.

UML

You may find the UML diagram for the code helpful as well:

!includesub common.puml!STYLE
!includesub before.puml!CLASSES

UGABookstore --> Visa : "dependsOn"
UGABookstore --> PayPal : "dependsOn"

Test Yourself

  1. How would the code above change if we wanted to support payments from other payment processors without using the PaymentProcessor interface? For example, the other payment processor could be Affirm.

  2. What if there were 20 additional payment processors?

Test Yourself Solution (Open after answering the question above)
  1. We would need to add another purchase method that takes in a reference to an Affirm object.

  2. We would need 20 additional purchase methods. Uh oh…

Now that you’ve seen the potential problem that can arise, we will dive deeper into this example in the next section to show you how interfaces provice an elegant solution to this problem!