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.
[apex]
badges.