Difference between Abstract, Virtual and Interface in APEX

Apex is an object-oriented programming language that allows developers to execute flow, transaction, and control statements on the Salesforce platform.

Devs who are used to Java or .NET development will find that programming in Apex is fairly straightforward. Also, beginners who have never coded before might be surprised by how easy it is to access and manipulate data with Apex.

In this article, we will give a brief description of Abstract, Virtual, and Interface in Apex.

Abstraction

In Apex, data abstraction is defined as the process of reducing the object to its essence, so that only the necessary characteristics are exposed to the users. Abstraction defines an object in terms of its properties,  behaviors, and interfaces.

Encapsulation

Encapsulation in Java is a mechanism of wrapping the data (variables) and code acting on the data (methods) together as a single unit. In encapsulation, the variables of a class will be hidden from other classes and can be accessed only through the methods of their current class.

Polymorphism

A class that extends another class inherits all the methods and properties of the extended class. Additionally, the extending class can override the existing virtual methods by using the override keyword in the method definition. Therefore, overriding a virtual method allows you to provide a different implementation for an existing method. This means that the behavior of a particular method is different based on the object you’re calling it on. This is referred to as polymorphism.

Inheritance

Inheritance is the ability to build new classes on top of existing ones. With that said, we can reuse existing code by extending the existing class and add extra functionality into your child’s class.


Interface vs Abstract vs Virtual

Below is a table, which contains a comparison between Interface, Abstract, and Virtual in Apex.

Interface
Use Cases
  1. When we need to guarantee a specific logic. For example, we can provide an interface to another team before it starts working on an implementation for particular methods. Therefore, they won’t have any blockers and don’t need to wait for our code modifications.
  2. When we need to create new data types with some set of methods, but with different implementations.
Description

Interface in Apex is a collection of unimplemented methods and it contains the method signature, while the body of each method is empty. Therefore, when we use Interface in Apex, another Apex class must implement it by providing the body for all the methods contained in Apex interfaces.

Good examples are Database.Batchable, Queueable, Schedulable interfaces. This way Salesforce forces us to implement specific methods.

Benefits
  • We program to interfaces, not implementations!
  • The class can implement a few interfaces! As result, it allows our class to have different behaviors.
  • Code is easier to change when it depends only on interfaces. Doesn’t have reference to specific classes, but to interface.
  • Good choice if the API will not change for a while.
Limitations
  • Adding a new method to an interface can be difficult because we need to change all the classes that implement that interface.
Code Structure
// Interface
public interface Worker{
   // Method's signature
   DoubleincreaseWorkerSallary(Double currentSalarry);
}

//Company A
public class CompanyAWorker implements Worker{
   public Double DoubleincreaseWorkerSallary(Double currentSalarry) {
      return currentSalarry * 2.1;
   }
}

//Company B
public class CompanyBWorker implements Worker {
   public Double increaseWorkerSallary(Double currentSalarry) {

      return currentSalarry * 1.2;
   }
}

// Because each class implements Worker interface, we can do something like that:
Worker workerA= new CompanyAWorker();
Worker workerB= new CompanyBWorker();

workerA.increaseEmployeeSallary(1000.0); //2100
workerB.increaseEmployeeSallary(1000.0); //1200
Abstract
Use Cases
  1. Classes that contain common methods with similar code logic.
  2. New methods can be added in the future.
  3. Sometimes there might be some logic that must be class-specific. For example, Company 1 and Company 2 have the same payment() implementation, but they are different for IncreaseSalary(). In this case, we can mark IncreaseSalary() method as abstract.
Definition

Upon creating an abstract class, we need to use the abstract definition modifier. An abstract class can contain methods that only have a signature and are defined as abstract. Child Class must implement all methods declared as abstract!

We can have different signatures for our methods:

    • private – child class doesn’t have access to method signed as private.
    • protected – child class has access to parent class method, but any other class doesn’t have access.
    • public – In other words, making the method accessible by any other class.

An abstract class can also include other methods, which contain logic. If we want to allow child class access to those methods we need to use protected or public keywords.

Benefits
  • Can contain both virtual and abstract methods.
  • It is not mandatory but virtual methods can be overwritten.
  • The abstract class allows us an easy way to update our logic for all child classes.
Limitations
  • Cannot be initialize directly: new TestAbstractClass()
  • The methods in the class can only be used if the class is extended by another class.
Code Structure
//Abstract Parent class
public abstract class TestAbstractClass {

    protected String test1;
    public String test2;

    TestAbstractClass() {}

    TestAbstractClass(String test1, String test2) {
       this.test1 = test1;
       this.test2 = test2;
    }

    abstract public String myAbstractMethod();

    public virtual String myVirtualMethod() {
       return 'virtual method from abstract class';
    }

    private String myPrivateMethod() {
       return 'private method from abstract class';
    }

    protected String myProtectedMethod() {
       return 'protected method from abstract class';
    }

    public String myPublicMethod() {
       return 'public method from abstract class';
    }
}
//Child class
public class ExampleClass extends TestAbstractClass {

   ExampleClass(String test1, String test2) {
     //Abstract class constructor can use super. 
     //Remember! Abstract class cannot be initialized, 
     //so this is the only scenario when we can use abstract class constructor!
      super(test1, test2);
   }

   public String myAbstractMethod() {
      return 'Abstract method implemented in child class!';
   }

   public override String myVirtualMethod() {
      return 'Virtual method overridden in child class!';
   }   

   public String invokeMethodFromAbstractClass() {
      String methods = '';
      methods += myPrivateMethod();//error, private method is not accessible in child class
      methods += myProtectedMethod();
      methods += myPublicMethod();

      return methods; //protected method from abstract class public method from abstract class
   }
}
ExampleClass example = new ExampleClass('Hello', 'World');
System.debug(example.test1); //error. Property test1 can be accessed only in child class.
System.debug(example.test2); //output: 'World';
System.debug(example.myAbstractMethod()); //output: 'Abstract method implemented in child class!'
System.debug(example.myVirtualMethod()); //output: 'Virtual method overridden in child class!'
System.debug(example.myPrivateMethod()); //error. It can be used only in parent class
System.debug(example.myProtectedMethod()); //error. It can be used only in parent and child classes
System.debug(example.myPublicMethod()); //output: 'public method from abstract class'

TestAbstractClass abstractClass = new TestAbstractClass();//error. Abstract class cannot be initialized
Virtual
Description

The virtual definition modifier declares that this class allows extension and overrides. As result, a class that extends another class inherits all the methods and properties of the extended class. A Virtual class is some kind of “full” class. Therefore, when creating a virtual class, we need to use the virtual definition modifier.

Benefits
  • Extend a class to provide more sophisticated behavior.
  • Virtual methods can be overridden. As a result, overriding a virtual method allows us to provide a different implementation for an existing method.
  • The virtual class can be initialized directly. For example, new TestVirtualClass();
  • We can use only virtual methods.
Limitations
  • Virtual classes can only extend one class, but they can implement more than one interface!
Use Cases
  1. Our classes can have common methods with similar logic.
  2. Possibility to initialize parent class with new. For example, the class needs to be used directly.
  3. We have a basic logic, but some methods can be overridden by the child class (virtual methods).
Code Structure
//Parent Virtual Class
private virtual class TestVirtualClass {
   
   protected String test1;
   public String test2;

   TestVirtualClass() {}

   TestVitrualClass(Strint test1, String test2) {
       this.test1 = test1;
       this.test2 = test2;
   }

   public virtual String myVirtualMethod() {
      return 'virtual method from virtual class';
   }

   private String myPrivateMethod() {
      return 'private method from virtual class';
   }

   protected String myProtectedMethod() {
      return 'protected method from virtual class';
   }

   public String myPublicMethod() {
      return 'public method from virtual class';
   }
}
//Child class
public class ExampleClass extends TestVirtualClass {
   
   ExampleClass(String test1, String test2) {
      //Virtual class constructor can use super. 
      super(test1, test2);
   }

   public override String myVirtualMethod() {
      return 'Virtual method overridden in child class!';
   }   

   public String invokeMethodFromAbstractClass() {
      String methods = '';
      methods += myPrivateMethod();//error, private method is not accessible in child class
      methods += myProtectedMethod()
      methods += myPublicMethod();

      return methods; //protected method from abstract class public method from abstract class
   }
}
ExampleClass example = new ExampleClass('Hello', 'World');
System.debug(example.test1); //error. Property test1 can be accessed only in child class.
System.debug(example.test2); //output: 'World';
System.debug(example.myVirtualMethod()); //output: 'Virtual method overridden in child class!'
System.debug(example.myPrivateMethod()); //error. It can be used only in parent class
System.debug(example.myProtectedMethod()); //error. It can be used only in parent and child classes
System.debug(example.myPublicMethod()); //output: 'public method from virtual class'

TestVirtualClass virtualClass = new TestVirtualClass();
System.debug(virtualClass.myVirtualMethod()); //output: 'virtual method from virtual class' 
System.debug(virtualClass.myPrivateMethod()); ////error. It can be used only in parent class
System.debug(virtualClass.myProtectedMethod()); //error. It can be used only in parent and child classes
System.debug(virtualClass.myPublicMethod()); //output: public method from virtual class'
Conclusion

Interface, Abstract, and Virtual classes are different methods to make our code more generic, reusable, and clear to other developers.

  • Interface provides another layer of abstraction, therefore it makes it easier to change our implementation.
  • Abstract class allows us to force the developer that is using the class, to implement some methods.
  • Virtual is the lightest solution, which gives us the possibility to override some method provided by the parent class.
Want to learn more?

Learn about Salesforce DX commands for removing old org from list
Read more about Apex Class Definition

Share this article...

Salesforce Mentor, with 10 years Salesforce experience, Hardcore Admin & Guru Developer, Geek, Animal lover, and dog & cat rescuer activist. Lifetime student, Stand-Up comedian wannabe, Photographer, Gamer, Anime lover, and coffee addict. Spreading Salesforce love and teaching beyond my capacity. Aiming to become Tech Architect!

Leave a Reply

Your email address will not be published. Required fields are marked *