17

I'm studying for my Platform Dev I exam, and I've been reading about interfaces. I understand how they work in abstraction, but what I don't understand is why you would use them. The documentation says they "provide a layer of abstraction to your code," but that doesn't really tell me anything. If you have to define all of the methods in your implementing class anyway, how does an interface make your code any cleaner?

Thanks for your help!

  • 8
    Have you read this answer about why you'd use abstract/interface? Does this help you? – sfdcfox May 23 '16 at 17:07
  • 1
    The answer sfdcfox links to is well worth reading but I'm not sure it answers the question "how does an interface make your code any cleaner?". (I clicked "reopen" and the question re-opened straight away which was not my intent; thought I was nominating the question to be reopened.) – Keith C May 23 '16 at 17:36
  • 1
    @KeithC That's because you're too powerful of a user. I have to always check which tags are on a question before I click close, because I can immediately close certain types without nomination. – sfdcfox May 23 '16 at 17:42
  • You guys and your gold [apex] badges. – Adrian Larson May 23 '16 at 17:46
  • 1
    @KeithC BADGE HAMMER FTW. With great power comes great responsibility. – Adrian Larson May 23 '16 at 17:57
19

Lets say you have some classes defined that provide the same method, but aren't otherwise related. E.g (based off a StackOverflow answer)

interface Flyable {
    void Fly();
}

public class Bird extends Reptile implements Flyable {
    public void Fly() {
        //Flap wings
    }
}

public class Plane extends Machine implements Flyable {
    public void Fly() {
        // throttle, elevators, rudder, ailerons, flaps, ...
    }
}

A Bird and a Plane aren't related by a common base class, so that can't inherit the implementation of flight. Nor should they, as their implementations to flight are fairly different. But they can both fly.

The interface allows you to perform a common operation on otherwise unrelated objects. E.g.

List<Flyable> flyingThings = GetBirdInstancesAndPlaneInstancesMixed();
for(Flyable item in flyingThings) {
   item.Fly();
}

This is exactly where it makes your code cleaner. How would you otherwise make this list of unrelated things fly? You would have a List<Object> where you need to figure out the type you are dealing with and try and call the applicable method. Getting the runtime-type of an Object in Apex is a pain and there is no switch statement to jump through all the possible options.

Better to have a common interface and let any class that implements it deal with how it gets done.

Thinking about the benefit of Comparable being an interface rather than an abstract base class is similar. You can't have multiple inheritance in Apex, so if it was a base class rather than interface, anything that wanted to be Comparable would ultimately need to extend from it. That's not really what you want, as now all sorts of otherwise unrelated objects are interchangeable at the base level. With Comparable as an interface you can still call compareTo() on anything that implements it to sort it without needing to know anything else about how that object.

Reasons to use an interface:

  • Behavior Contract - A common method is needed on otherwise unrelated objects. The implementation of that method could be significantly different. As such, there is little benefit in inheriting the implementation (behavior).
  • Coupling - If code is only dependent on the interface then it is easier to change the implementation, as there no/fewer references to a specific class. E.g. I can change the way a plane flys without any risk of making birds fall out of the sky.
18

Interfaces abstract an algorithm from data. They provide a "contract" between an object and method that uses that object. Implementing an interface guarantees that a given object has a specific type of behavior. In the standard library, we see this in the Schedulable, Queueable, Batchable, Comparable, Iterable, and Iterator interfaces, to name a few.

For example, implementing the Schedulable interface guarantees that System.schedule knows how to run the code inside of the class, while implementing Comparable allows List.sort to know how to sort a collection of that object. This allows a given method to know how to interact with objects that may well be implemented after the original code was written. Without interfaces, you'd have to write a new copy of a given algorithm for every new data type.

Without Comparable, List.sort would have to have a different implementation of the code for every data type, and would also require developers to write their own sort algorithm every time they created a new class that they wanted to be able to sort. Most of the asynchronous features of Salesforce (Queuable, Schedulable, and Batchable) would not be possible in a strongly typed language like Apex Code without interfaces or reflection. Since we don't have proper reflection in Apex Code, interfaces are absolutely required in order to implement these features within the confines of the language.

Interfaces are not needed in languages like Ruby or JavaScript, because these languages can inspect objects dynamically to determine if they support a certain method. However, strongly typed languages like C++, Java, and Apex Code need a way for the compiler to guarantee that a given object supports a given method, otherwise it could not reasonably guarantee that the code would run without runtime exceptions because of simple typos.

In summary, interfaces allow us to plug in user-defined types into algorithms, which reduces the amount of code that has to be maintained. We only need one copy of an algorithm to support many diverse types of objects without the developer needing to be concerned about the underlying data.


As a very specific example, I once designed a configuration page that enabled use to toggle triggers and integration callouts (external) in a standardized format. While all integration callouts were based on a single abstract parent class, and all trigger classes were based on a single virtual parent class (to allow copy-paste definitions for each object in the system that needed a trigger), they needed a common definition to provide on-screen help in a way that didn't rely on modifying the Visualforce's source every time a new class was added. Using an interface (call it IHelpText), we were able to add functionality that was common to two entirely different types of classes without having to provide an abstract parent class to both the callout classes and trigger classes. The code also allowed those classes to be upgraded to provide help "in the future", so it didn't have to be implemented at the time the new class was created.


Using a set of interfaces, I built a modular batch process. This allows me to perform simple tasks in production without deploying new code, without exporting, transforming, and importing data, reduce the number of batch classes I needed to have in the system. For example, I would have two classes that look like this:

public class GenerateRecordsFromQuery implements Batch.Generator {
    String query;
    public GenerateRecordsFromQuery(String query) {
        this.query = query;
    }
    public Object generate() {
        return Database.getQueryLocator(query);
    }
}
public class UpdateRecordsAction implements Batch.Action {
    public void perform(Object[] records) {
        update (SOBject[])records;
    }
}

This allows me to write code (in an Execute Anonymous window) in production that looks like this:

Database.executeBatch(
    new Batch(
        new GenerateRecordsFromQuery('select id from lead where isconverted = false'),
        new UpdateRecordsAction()));

By building single modules, I can use them in any combination I desire. I can give them whatever constructor I want and use them in any reasonable combination.


Finally, one important thing to consider is that interfaces can be mixed and matched. You can't do that with abstract or virtual classes, because each child can only inherit from one parent. However, one class can implement any number of interfaces, allowing a single class to have multiple behaviors. This makes it easy for classes that have nothing in common except for a single feature can share that feature without a common parent.

  • 2
    Any examples where you have created an interface in your own code? I might be misinterpreting the question, but I think there is an element of "when would I create an interface" as well as "when might I write a class that implements a platform interface". – Keith C May 23 '16 at 21:45
  • 1
    @KeithC Sure. Give me a bit and I'll edit. – sfdcfox May 23 '16 at 22:04
  • In five-ish years of writing Apex I've needed an interface only once, and that was a class that doubled as the source for a WSDL export and a class to use internally. The reason I so infrequently use interfaces is that in addition to class protocol (which an interface defines) I frequently want implementation, too, and interfaces don't provide implementation--only virtual/abstract classes do. – tggagne May 26 '16 at 2:48
  • @tggagne I agree that interfaces are relatively rare. I have used well over a dozen, but I've written hundreds, if not thousands of classes. However, my modular Batch process, for example, would not be as flexible if I depended on abstract/virtual classes, because the inheritance would create dependencies. Interfaces are certainly more challenging to use, but they do have advantages over abstract and virtual classes, such as sharing algorithms across unrelated types. – sfdcfox May 26 '16 at 3:12
6

Hard to know what sort of answer is being looked for in the exam. In a couple of large code bases we have 35 times more class declarations than interface declarations. So one answer to when you would use them is "not very often", though it really depends on what problem your code is focussed on.

Our main use is where we have many implementations (in classes) of a piece of behaviour that can all follow a fixed public shape (the interface).

Interfaces should only be introduced where they help make code clearer. (And for some perspective here is an entertaining Robert C. Martin piece 'Interface' Considered Harmful.)

PS

In support of Adrian's point, in those code bases there are 4x as many implements as interfaces (though some of those will be implements of a platform provided interface).

  • 4
    Interface declarations should be relatively rare. Implementations of them should be more widespread. – Adrian Larson May 23 '16 at 17:24
6

This question is quite broad, but I have written or worked with few interfaces which really improve my experience with Apex. The big win from all of them is that they allow other programs to extend a library with minimal effort.

Your interface provides you with guaranteed functionality, in terms of input/output pairings. This contract allows you to take a generic object and use it in a well defined way.

The provider architecture I implemented in my SObjectFactory library is a simple example that will let you see both sides of how you can benefit from an interface.

The interface can be as simple as:

public interface IFieldProvider { Object getValue(); }

A basic implementation example (others here):

public class UniqueNumberProvider implements IFieldProvider
{
    Integer counter;
    public UniqueNumberProvider() { this(0); }
    public UniqueNumberProvider(Integer start) { this.counter = start; }
    public Object getValue() { return counter++; }
}

How it's used behind the scenes (simplified):

public static SObject build(SObjectType sObjectType, Map<SObjectField, Object> fields)
{
    SObject record = sObjectType.newSObject();
    for (SObjectField field : fields.keySet())
    {
        Object value = fields.get(field);
        if (value instanceOf IFieldProvider)
            value = ((IFieldProvider)value).getValue();
        record.put(field, value);
    }
    return record;
}

What makes this architecture really useful is if you want to write your own provider. This pattern made it easy for me to write as many providers as I could think of and plug them in as needed in my tests.

You can see a similar advantage in the Selector library.

  • I'm on the "no" side of Should interface names begin with an “I” prefix?. – Keith C May 23 '16 at 17:23
  • @KeithC IMO it's context dependent. I do eschew them sometimes and find it much cleaner. I think it helps if you namespace it. – Adrian Larson May 23 '16 at 17:25
  • @KeithC And the most popular comment: +1 for "All of this being said, I tend to prefix my C# interfaces with I anyway because that is the .NET convention used and advocated by Microsoft". This is reason enough for me in C#. By following this common standard it is more likely that other .NET programmers with identify the interface. Many of us find it distasteful, but its widespread use makes it recognizable. Most important is to make sure you don't start it with an "i" prefix instead! – Adrian Larson May 23 '16 at 18:12
  • Aside from the idea that an interface shouldn't be recognisable, there is the practical matter of the lack of packages in Apex meaning that we have to deal with long lists of classes usually ordered alphabetically. My preference is to not have a separate clump of "I..." names. Didn't Microsoft use to prefix C++ classes with "C" - lets keep doing that too... :) – Keith C May 23 '16 at 18:25
  • 1
    Point taken about convention for the sake of convention being somewhat moronic. I've written approximately one top level interface ever, so I'm not too worried about bloating the class list. And in terms of whether you want your interface recognizable, I'm not sure why you would write an interface if you don't want anyone to implement it. To be fair, though, the only reason I implemented it that way in the first place is that it was a more collaborative environment when I built that library. I'm on the same page. I don't think it creates a very cohesive mental model. – Adrian Larson May 23 '16 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.