Interfacing with Interfaces

Interfacing with Interfaces

This is a continuation on my series of articles on object-oriented programming. The first article, discusses how you can use role-playing game characters as a metaphor for object classes, the second, discusses how party-systems and roles introduce polymorphism and class hierarchy, the third discusses how to create Java classes using a role-playing game character sheet as a model, the fourth introduces how to extend classes based on common characteristics, the fifth discusses building collections using superclasses typing and the purpose of abstract classes, the sixth covers how to create private and protected members to prevent access to class internals.

When we originally defined our game, we created the concept of a party. In many role-playing games, the party is the group of active players that are working together to complete quests, defeat enemies and progress through the game.

We defined the party as requiring three types of characters. The first is a tank, which is a character that can take a lot of damage but can only attack at short range. The second is a range, which is a character that can not take a lot of damage but can attack from a distance. The last is a healer, which can heal the injuries sustained by another party member.

What is interesting about these types is that they can apply to more than one type of character class. Take the Paladin class for example, that is a tank and a healer, so we need to have a way to create instances of character classes but have a way to categorize them so they can be interchanged with other classes in a typed container.

We have a basic ArrayList to hold our party, but let's create a new class to handle all of our Party characteristics:

public class Party {
    
    Party() {}
}

Inside of this class, we will need to create variables for each type of character that forms the party. Let's start with one, the tank. We can create a class-scoped variable called tank, and type it to the PlayerCharacter class:

public class Party {
 
    PlayerCharacter tank;
 
    Party() {}
}

While this wouldn't create any syntax or runtime errors, it does go against the rules we created for the class. We only want two types of characters to be allowed as a tank: the paladin and fighter. So how do we create a way to type to just these?

The answer is to create an interface.

Interfaces are separate Java files that you apply, or implement with a class. That then tells Java that this class applies all of the requirements defined by the interface, and you can then type containers, collections, or anything that you can type to an interface.

Creating an interface requires a new file in our program, we will create one called Tank.java. If you are using an IDE, make sure you create it as an interface file and not as a class file:

public interface Tank {
}

This is not a class, but is instead an interface, defined by the interface statement on the first line.

Interfaces are built differently than classes. Interfaces don't have constructors, and you only need to provide the public methods that a class that implements the interface needs to have to make it "legal" to implement. The methods don't need to have any code in them and they don't need to include access modifiers, it is just used as a reference check for Java to know that what you are creating and assigning to an interface typed container is valid.

Our Fighter and Paladin classes contain two public methods: showStats() and addXP(), so we need to add those definitions in the interface:

public interface Tank {
    void showStats();
    void addXP(int deltaXP);
}

That is all we need to create in our interface file, but now we need to implement it on a class. Let's start with the Fighter:

To implement an interface, you need to add the implement statement and the name of the interface that you are applying to the class in the first line of the code:

public class Fighter extends PlayerCharacter implements Tank {

That's it! Now we can go back to our Party class and type to our new interface:

public class Party {
 
    Tank tank;
 
    Party() {}
}

You'll see that the code doesn't show any errors, and the new container will accept anything that implements the Tank interface.

We can update the Paladin class in the same way:

public class Paladin extends PlayerCharacter implements Tank {

When you implement an interface, you can implement more than one with a class. So for the Paladin, when the Healer interface is created, you would add that after Tank, adding a comma in between them.

Now we can create instances of Fighter and Paladin to include in our program:

public class Party {
 
    Tank tank;
 
    Party() {
        tank = new Fighter("Sentri");
        tank = new Paladin("Dupre");
        tank = new Mage("Jaana");
    }
}

In the code above, the Fighter and Paladin instances are legal, because they implement the Tank interface. The Mage however, generates an error, because the class does not implement the interface.

We can now create public and private access modifiers to our Party class. First we need to make the container private, and then create a public method to allow us to add a character to the slot in the party:

public class Party {
 
    private Tank tank;
 
    Party() {}
 
    public void addTank(Tank pc) {
        tank = pc;
        System.out.println("Tank added to party.");
    }
}

Now we can replace our code in Main with our new Party class:

public class Main {
 
    public static void main(String[] args) {
        Party myParty = new Party();
        myParty.addTank(new Fighter("Sentri"));
    }
}

If we run this program, we will see the following message:

A new fighter named Sentri has been created!
Tank added to party.
 
Process finished with exit code 0

Interfaces can be considered categories for your classes. You define what those category requirements are in the interface, and then tell your classes that they are part of the category by implementing the interface for it.

To view or add a comment, sign in

Others also viewed

Explore topics