91. Interfaces

Interfaces provide a set of method signatures that are intended to be implemented by classes - they are an extremely useful construct that allows you to define a “contract” between your code and other developers.

Let’s take a look at an example:

An interface declaration
interface SocialNetwork {
    Member friend(Member friend)
    Member unFriend(Member enemy)
}

The syntax looks much like that of a class but you’ll notice two key differences:

  1. The keyword interface is used to declare an interface
  2. There are two method signatures (friend and unFriend) but I haven’t provided the code body for the method

That last point is an important one: interfaces don’t define implementations, they are used to define an API that is implemented by one or more classes. Well thought out interfaces are integral to code that can be reused and maintained over time. Some developers will start a new coding effort by determining the interfaces they’ll need by asking “what elements will interact and how?”.

An interface can’t be instantiated (e.g. SocialNetwork network = new SocialNetwork()) as it doesn’t actually do (implement) anything. In order to implement an interface, the implements keyword, followed by the interface’s name, is used in the class declaration:

Implementing the interface
class Member implements SocialNetwork {
    String name
    def friends = [] as Set

    @Override
    Member friend(Member friend) {
        friends << friend
        friend
    }

    @Override
    Member unFriend(Member enemy) {
        friends -= enemy
        enemy
    }
}

In class Member implements SocialNetwork we bind the Member class to the SocialNetwork interface. This then means that the class needs to provide implementations of the friend and unFriend methods. In the example above you’ll note that I’ve annotated each implemented method with @Override. This indicates to the Groovy compiler that those two methods are related to method signatures from an interface that is being implemented1.

Groovy (and Java) classes can implement more than one interface by listing them after the implements keyword - just use a comma (,) between each interface:

Implementing more than one interface
interface SocialNetwork {
    Member friend(Member friend)
    Member unFriend(Member enemy)
}

interface Posts {
    Map getPosts()
    void addPost(String title, String body)
}

class Member implements SocialNetwork, Posts {
    String name
    def friends = [] as Set
    Map posts = [:]

    @Override
    Member friend(Member friend) {
        friends << friend
        friend
    }

    @Override
    Member unFriend(Member enemy) {
        friends -= enemy
        enemy
    }

    @Override
    void addPost(String title, String body) {
        posts << [title: body]
    }
}

I’ve provided a full code listing of the example below so that you can take this for a test spin in the groovyConsole:

Full code listing plus usage
interface SocialNetwork {
    Member friend(Member friend)
    Member unFriend(Member enemy)
}

interface Posts {
    Map getPosts()
    void addPost(String title, String body)
}

class Member implements SocialNetwork, Posts {
    String name
    def friends = [] as Set
    Map posts = [:]

    @Override
    Member friend(Member friend) {
        friends << friend
        friend
    }

    @Override
    Member unFriend(Member enemy) {
        friends -= enemy
        enemy
    }

    @Override
    void addPost(String title, String body) {
        posts << [title: body]
    }
}

def jim = new Member(name: 'Jim')
def gina = new Member(name: 'Gina')
def andrew = new Member(name: 'Andrew')

jim.with {
    println 'Jim makes some friends: '
    friend(gina)
    friend(andrew)
    friends.each { println " - $it.name" }

    println '\nJim makes an enemy of Andrew'
    unFriend(andrew)

    println '\nJim now has these friends: '
    friends.each { println " - $it.name " }

    println '\nAdding a post'
    addPost('My weekend', 'Just hung out and stuff')
    println getPosts()
}
  1. It’s also used for methods overriding those declared in a superclass.