Understanding Abstraction in Java: A Key OOPS Concept

Understanding Abstraction in OOP Concept
Chinmaya By Chinmaya
8 Min Read

Introduction

Abstraction is one of the four pillars of Object-Oriented Programming (OOP), alongside Encapsulation, Inheritance, and Polymorphism.
It helps developers design systems that are simple to understand, easy to use, and maintainable.

Let’s dive into the concept of abstraction in Java, explained in simple terms with examples.

What is Abstraction?

Abstraction is the process of hiding the complex implementation details and showing only the essential features of an object. Think of it like driving a car: you don’t need to know how the engine works to drive it. You just need to know how to use the steering wheel, pedals, and gears. The car’s internal mechanics are “abstracted” away from you.

In programming, abstraction allows you to focus on what an object does rather than how it does it. It simplifies complex systems by breaking them into smaller, manageable parts.

Abstraction in Object-Oriented Programming (OOP)

Abstraction is one of the four pillars of OOP. The other three are:

    1. Encapsulation: Bundling data and methods that operate on that data into a single unit (e.g., a class).

    2. Inheritance: Creating new classes based on existing ones to promote code reuse.

    3. Polymorphism: Allowing objects to take on multiple forms (e.g., method overriding).

Abstraction works closely with encapsulation to hide unnecessary details and expose only what’s needed.

Why Do We Need Abstraction?

    1. Simplifies Code: It hides the complex implementation details.
    2. Improves Maintainability: Changes in the internal logic don’t affect the exposed functionality.
    3. Enhances Security: Users only interact with the essential features, ensuring sensitive details are not accessible.

How Abstraction Works in Salesforce Apex

In Salesforce Apex, abstraction is achieved using abstract classes and interfaces.
These allow you to define a blueprint for what a class should do without specifying how it should do it.

Let’s explore both concepts with examples.

1. Abstract Classes

An abstract class is a class that cannot be instantiated on its own. It serves as a template for other classes. You can define methods in an abstract class, but you don’t have to implement them—this is left to the subclasses.

Example:

Imagine you’re building a system to manage different types of vehicles. You can create an abstract class called Vehicle that defines what all vehicles should do, but leaves the implementation to specific vehicle types.

				
					// Abstract class
public abstract class Vehicle {
    // Abstract method (no implementation)
    public abstract void start();

    // Concrete method (has implementation)
    public void stop() {
        System.debug('Vehicle stopped.');
    }
}

// Subclass for Car
public class Car extends Vehicle {
    public override void start() {
        System.debug('Car started with a key.');
    }
}

// Subclass for Bike
public class Bike extends Vehicle {
    public override void start() {
        System.debug('Bike started with a kick.');
    }
}
				
			

Here’s how you can use these classes:

				
					Vehicle myCar = new Car();
myCar.start(); // Output: Car started with a key.
myCar.stop();  // Output: Vehicle stopped.

Vehicle myBike = new Bike();
myBike.start(); // Output: Bike started with a kick.
myBike.stop();  // Output: Vehicle stopped.
				
			

Explanation:

    • In this example:

      • The Vehicle class defines a blueprint for all vehicles.

      • The start method is abstract, meaning each subclass must provide its own implementation.

      • The stop method is concrete, meaning it’s shared by all subclasses.

2. Interfaces

An interface is like a contract. It defines a set of methods that a class must implement, but it doesn’t provide any implementation itself. Interfaces are useful when you want to enforce certain behaviors across unrelated classes.

Example

Let’s say you’re building a notification system. You can define an interface called Notification that specifies what all notifications should do.

				
					// Interface
public interface Notification {
    void send(String message);
}

// Class for Email notifications
public class EmailNotification implements Notification {
    public void send(String message) {
        System.debug('Sending email: ' + message);
    }
}

// Class for SMS notifications
public class SMSNotification implements Notification {
    public void send(String message) {
        System.debug('Sending SMS: ' + message);
    }
}
				
			

Here’s how you can use these classes:

				
					Notification email = new EmailNotification();
email.send('Hello, this is an email!'); // Output: Sending email: Hello, this is an email!

Notification sms = new SMSNotification();
sms.send('Hello, this is an SMS!'); // Output: Sending SMS: Hello, this is an SMS!
				
			

Explanation:

    • In this example:

      • The Notification interface defines a send method that all notification classes must implement.

      • The EmailNotification and SMSNotification classes provide their own implementations of the send method.

Why is Abstraction Important?

Abstraction helps you:

    1. Simplify Complex Systems: By hiding unnecessary details, abstraction makes your code easier to understand and maintain.

    2. Promote Reusability: Abstract classes and interfaces allow you to define common behaviors that can be reused across multiple classes.

    3. Enforce Consistency: Interfaces ensure that all implementing classes adhere to the same contract, reducing errors and improving reliability.

Key Differences: Abstract Classes vs Interfaces

Real-World Example in Salesforce

Imagine you’re building a Salesforce app to manage different types of reports (e.g., PDF, Excel, and CSV). You can use abstraction to handle all reports in a unified way.

				
					// Abstract class
public abstract class Report {
    public abstract void generate();
}

// Subclass for PDF reports
public class PDFReport extends Report {
    public override void generate() {
        System.debug('Generating PDF report...');
    }
}

// Subclass for Excel reports
public class ExcelReport extends Report {
    public override void generate() {
        System.debug('Generating Excel report...');
    }
}

// Subclass for CSV reports
public class CSVReport extends Report {
    public override void generate() {
        System.debug('Generating CSV report...');
    }
}
				
			

Now, you can generate reports without worrying about the specific type:

				
					Report pdfReport = new PDFReport();
Report excelReport = new ExcelReport();
Report csvReport = new CSVReport();

pdfReport.generate();  // Output: Generating PDF report...
excelReport.generate(); // Output: Generating Excel report...
csvReport.generate();  // Output: Generating CSV report...
				
			

Conclusion

Abstraction is a powerful concept in Salesforce Apex that helps you simplify complex systems, promote reusability, and enforce consistency. By using abstract classes and interfaces, you can define blueprints for your objects and hide unnecessary details, making your code cleaner and more maintainable.

Whether you’re building a vehicle management system, a notification system, or a reporting tool, abstraction will help you write better, more organized code. So, the next time you’re designing a class, think about what you can abstract away to make your life easier!

Happy coding! 🚀

Key Takeaways:

Use abstract classes when you have a shared base with common functionality and need to enforce some method implementations.

Use interfaces for creating a contract that multiple unrelated classes can implement.

Share This Article
Follow:
Chinmaya is working as a Senior Consultant with a deep expertise in Salesforce. Holding multiple Salesforce certifications, he is dedicated to designing and implementing cutting-edge CRM solutions. As the creator of Writtee.com, Chinmaya shares his knowledge on educational and technological topics, helping others excel in Salesforce and related domains.
Leave a comment