OOP Abstraction: Fundamentals, Interfaces & Design by Contract
This article is a definition of terms for abstraction in object-oriented programming – including exam questions and tags.
In a Nutshell
Abstraction reduces complex systems to their essential properties and operations, it defines the what of an interface, the how remains hidden and can be developed independently.
Compact Technical Description
Abstraction is a fundamental concept that reduces complex reality to relevant properties and hides unimportant details. In OOP, abstraction manifests itself through:
- Interfaces: Pure contract definition without implementation
- Abstract Classes: Partial implementation with abstract methods
- Design by Contract: Preconditions, postconditions, invariants
Abstraction enables independent development of implementations, as long as the contract is maintained. It supports the Open Closed Principle: Extensions through new implementations without changing existing code.
Separating the what (interface) from the how (implementation) is the core of good software architecture. Abstraction reduces cognitive load, promotes reusability, and enables flexible, testable systems.
Exam-Relevant Key Points
- What vs How: Interface defines what, implementation how
- Interfaces: Pure contract definition, no implementation
- Abstract Classes: Concrete and abstract methods mixed
- Design by Contract: Preconditions, postconditions, invariants
- Open Closed Principle: Extendable without modification
- Abstraction vs Encapsulation: Abstraction hides complexity, encapsulation protects data
- Polymorphism: Different implementations of an interface
- Dependency Inversion: Dependency on abstractions, not concretions
Core Components
- Interface: Defines method signatures without implementation
- Abstract Class: Can contain partially implemented methods
- Concrete Class: Implements all abstract methods
- Contract: Guaranteed behavior of the implementation
- Preconditions: Requirements for method call
- Postconditions: Guarantees after method execution
- Invariants: Conditions that must always hold
- Dependency Injection: Passing abstractions instead of concretions
Practical Example
// Interface: Defines the contract
interface DatabaseConnection {
void connect(String url, String user, String password);
void disconnect();
ResultSet executeQuery(String sql);
void executeUpdate(String sql);
}
// Abstract Class: Common functionality
abstract class AbstractDatabase implements DatabaseConnection {
protected boolean connected = false;
protected String url;
@Override
public void connect(String url, String user, String password) {
if (connected) {
throw new IllegalStateException("Already connected");
}
this.url = url;
// Check preconditions
validateConnectionParameters(url, user, password);
// Abstract method implemented by subclasses
doConnect(url, user, password);
connected = true;
// Postcondition: Connection must be established
assert connected : "Connection failed";
}
@Override
public void disconnect() {
if (!connected) {
throw new IllegalStateException("Not connected");
}
doDisconnect();
connected = false;
}
// Abstract methods for implementation
protected abstract void doConnect(String url, String user, String password);
protected abstract void doDisconnect();
// Common validation
private void validateConnectionParameters(String url, String user, String password) {
if (url == null || url.trim().isEmpty()) {
throw new IllegalArgumentException("URL required");
}
if (user == null || user.trim().isEmpty()) {
throw new IllegalArgumentException("User required");
}
}
}
// Concrete implementation
class MySQLDatabase extends AbstractDatabase {
@Override
protected void doConnect(String url, String user, String password) {
System.out.println("MySQL connection is being established to: " + url);
// MySQL-specific connection establishment
}
@Override
protected void doDisconnect() {
System.out.println("MySQL connection is being disconnected");
// MySQL-specific disconnection
}
@Override
public ResultSet executeQuery(String sql) {
if (!connected) {
throw new IllegalStateException("Not connected");
}
System.out.println("Execute MySQL query: " + sql);
return null; // Real ResultSet implementation
}
@Override
public void executeUpdate(String sql) {
if (!connected) {
throw new IllegalStateException("Not connected");
}
System.out.println("Execute MySQL update: " + sql);
}
}
// Usage with Dependency Injection
class DatabaseService {
private final DatabaseConnection connection;
// Dependency on abstraction, not concretion
public DatabaseService(DatabaseConnection connection) {
this.connection = connection;
}
public void showData() {
connection.connect("jdbc:mysql://localhost:3306/db", "user", "pass");
ResultSet rs = connection.executeQuery("SELECT * FROM customers");
// Process data...
connection.disconnect();
}
}
Advantages and Disadvantages
Advantages
- Complexity Reduction: Unimportant details hidden
- Flexibility: Different implementations easily exchangeable
- Testability: Mocks and stubs easily created
- Maintainability: Changes in implementation don’t affect interface
- Teamwork: Parallel development of interface and implementation
Disadvantages
- Indirection: Additional layer increases complexity
- Overhead: More code for simple tasks
- Learning Curve: Abstract thinking requires practice
- Over-Engineering: Too many abstractions for simple problems
Frequently Asked Exam Questions
-
What is the difference between abstraction and encapsulation? Abstraction hides complexity (what), encapsulation protects data (how).
-
When do you use interface vs abstract class? Interface for pure contract definition, abstract class for common implementation.
-
What is Design by Contract? Definition of preconditions, postconditions, and invariants for software components.
-
How does abstraction support the Open Closed Principle? Extensions through new implementations without changing existing code.
Most Important Sources
- https://en.wikipedia.org/wiki/Abstraction_(computer_science)
- https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
- https://en.wikipedia.org/wiki/Design_by_contract