Inheritance, Polymorphism, and Abstraction
Object-Oriented Programming (OOP) in Salesforce Apex
Salesforce Apex is a powerful, object-oriented programming language that supports the core principles of Object-Oriented Programming (OOP). The three main OOP concepts that you can utilize in Apex are Inheritance, Polymorphism, and Abstraction. These concepts help you write modular, reusable, and maintainable code.
1. Inheritance in Salesforce Apex
Inheritance allows a new class (child class) to inherit properties and behaviors (fields and methods) from an existing class (parent class). This enables you to create a hierarchy of classes that share common functionality, reducing code duplication.
Example of Inheritance in Apex:
Let’s consider a scenario where you have a system that manages different types of accounts in a bank, such as a SavingsAccount and a CheckingAccount. Both account types share some common attributes like account number and balance, but they also have unique behaviors.
Parent Class:
public class BankAccount {
public String accountNumber;
public Decimal balance;
public BankAccount(String accNumber, Decimal initialBalance) {
this.accountNumber = accNumber;
this.balance = initialBalance;
}
public void deposit(Decimal amount) {
balance += amount;
System.debug('Deposited: ' + amount);
}
public void withdraw(Decimal amount) {
if (balance >= amount) {
balance -= amount;
System.debug('Withdrawn: ' + amount);
} else {
System.debug('Insufficient balance');
}
}
public void displayBalance() {
System.debug('Account Balance: ' + balance);
}
}
Child Class:
public class SavingsAccount extends BankAccount {
public Decimal interestRate;
public SavingsAccount(String accNumber, Decimal initialBalance, Decimal interestRate) {
super(accNumber, initialBalance);
this.interestRate = interestRate;
}
public void applyInterest() {
Decimal interest = balance * interestRate / 100;
deposit(interest);
System.debug('Interest Applied: ' + interest);
}
}
Usage Example:
SavingsAccount mySavings = new SavingsAccount('SA12345', 1000, 5);
mySavings.deposit(200); // Inherited method
mySavings.applyInterest(); // Method from child class
mySavings.displayBalance(); // Inherited method
Explanation:
- BankAccount is the parent class with properties like
accountNumber
andbalance
, and methods for basic operations likedeposit
,withdraw
, anddisplayBalance
. - SavingsAccount is the child class that inherits from
BankAccount
. It adds a new propertyinterestRate
and a methodapplyInterest
, which calculates and adds interest to the balance.
Key Points:
- The child class (
SavingsAccount
) has access to all public and protected members of the parent class (BankAccount
). - The
super()
keyword is used to call the parent class constructor from the child class.
2. Polymorphism in Salesforce Apex
Polymorphism allows objects of different classes to be treated as objects of a common superclass. It is often implemented through method overriding, where a child class provides a specific implementation of a method that is already defined in its parent class.
Example of Polymorphism in Apex:
Let’s extend the previous example by adding a CheckingAccount class.
Child Class:
public class CheckingAccount extends BankAccount {
public Decimal overdraftLimit;
public CheckingAccount(String accNumber, Decimal initialBalance, Decimal overdraftLimit) {
super(accNumber, initialBalance);
this.overdraftLimit = overdraftLimit;
}
// Overriding the withdraw method to allow overdrafts
public override void withdraw(Decimal amount) {
if (balance + overdraftLimit >= amount) {
balance -= amount;
System.debug('Withdrawn: ' + amount);
} else {
System.debug('Overdraft limit exceeded');
}
}
}
Polymorphism Example:
BankAccount myAccount;
// Polymorphic behavior: Treating different objects as BankAccount
myAccount = new SavingsAccount('SA12345', 1000, 5);
myAccount.withdraw(200); // Calls the withdraw method from BankAccount class
myAccount = new CheckingAccount('CA12345', 500, 200);
myAccount.withdraw(600); // Calls the overridden withdraw method in CheckingAccount class
Explanation:
- CheckingAccount overrides the
withdraw
method fromBankAccount
to allow withdrawals even if the balance is below the withdrawal amount, as long as it doesn’t exceed the overdraft limit. - Polymorphism allows you to use a single variable (
myAccount
) of the typeBankAccount
to refer to objects of eitherSavingsAccount
orCheckingAccount
. - The method that gets executed is determined by the actual object type at runtime (i.e., whether
myAccount
is aSavingsAccount
or aCheckingAccount
).
Key Points:
- Method Overriding: The child class (
CheckingAccount
) can provide a specific implementation of a method (withdraw
) that is already defined in the parent class (BankAccount
). - Runtime Polymorphism: The actual method that gets called depends on the object type at runtime, not on the reference type.
3. Abstraction in Salesforce Apex
Abstraction is the concept of hiding the complex implementation details of a class and exposing only the essential features. This is often achieved through the use of abstract classes and interfaces.
Example of Abstraction in Apex:
Let’s define an abstract class for different types of bank accounts.
Abstract Class:
public abstract class AbstractBankAccount {
public String accountNumber;
public Decimal balance;
public AbstractBankAccount(String accNumber, Decimal initialBalance) {
this.accountNumber = accNumber;
this.balance = initialBalance;
}
// Abstract method, to be implemented by child classes
public abstract void withdraw(Decimal amount);
public void deposit(Decimal amount) {
balance += amount;
System.debug('Deposited: ' + amount);
}
public void displayBalance() {
System.debug('Account Balance: ' + balance);
}
}
Concrete Child Class:
public class FixedDepositAccount extends AbstractBankAccount {
public Integer lockInPeriod; // In months
public FixedDepositAccount(String accNumber, Decimal initialBalance, Integer lockInPeriod) {
super(accNumber, initialBalance);
this.lockInPeriod = lockInPeriod;
}
// Implementation of the abstract method
public override void withdraw(Decimal amount) {
System.debug('Withdrawals are not allowed from Fixed Deposit Account until maturity.');
}
}
Usage Example:
FixedDepositAccount myFD = new FixedDepositAccount('FD12345', 10000, 12);
myFD.deposit(2000);
myFD.withdraw(500); // Calls the implemented withdraw method in FixedDepositAccount
myFD.displayBalance();
Explanation:
- AbstractBankAccount is an abstract class that cannot be instantiated directly. It contains an abstract method
withdraw
, which must be implemented by any non-abstract subclass. - FixedDepositAccount is a concrete class that extends
AbstractBankAccount
and provides a specific implementation of thewithdraw
method, which restricts withdrawals until maturity.
Key Points:
- Abstract Classes: Abstract classes serve as a blueprint for other classes. They can contain both abstract methods (which must be implemented by subclasses) and concrete methods (with full implementations).
- Interfaces: Salesforce Apex also supports interfaces, which can be used to define a contract that classes must adhere to. Interfaces only contain method signatures without any implementation.