1. From procedure to object
In procedural programming, data and functions live apart: any function may touch any piece of data. In OOP the program is a network of objects that shield their own state and communicate by passing messages.
| Criterion | Procedural | POO / OOP |
|---|---|---|
| Focus | Sequential functions | Objects with responsibilities |
| Data | Globally shared | Encapsulated in the object |
| Coupling | High, with side effects | Low, with high cohesion |
| Maintainability | Complex as it grows | Scalable and reusable |
2. The 4 pillars of OOP
Tap a pillar to jump straight to its slide.
3. Abstraction
A real car has thousands of details. A fleet-management system only cares about a few: abstraction picks which fields and actions enter the class and drops the rest.
// Only the fields fleet management needs
public class Vehiculo {
private String patente;
private String marca;
private double velocidadActual;
public void acelerar(double incremento) {
this.velocidadActual += incremento;
}
} 4. Encapsulation
State lives inside the capsule and is private. The only gates are the public methods, which validate every change before applying it.
Try the public methods: the balance only changes when validation passes.
private double saldo;
public void retirar(double monto) {
if (monto > 0 && monto <= this.saldo) {
this.saldo -= monto;
} else {
// invalid request: state stays untouched
}
} 5. Inheritance
A subclass gains its superclass state and behaviour through extends, and calls super(...) to initialise the inherited part. Step through to see what each child receives.
public class Telefono extends Dispositivo {
private String numero;
public Telefono(String marca, String numero) {
super(marca); // inherited part first
this.numero = numero;
}
@Override
public void encender() {
System.out.println("Telefono listo");
}
} 6. Polymorphism
The array is declared as Dispositivo, yet each slot holds a concrete object in memory. The JVM decides at runtime which encender() implementation runs: dynamic dispatch.
Dispositivo[] flota = { new Telefono(), new Laptop(), new Tablet() }; Telefono → "Screen on, searching for signal"
Laptop → "Booting the operating system"
Tablet → "Reading mode enabled"
One single call, three different answers.
| Overriding | Overloading | |
|---|---|---|
| Where | Between superclass and subclass | Within the same class |
| Signature | Identical | Different parameters |
| Resolved | At runtime (dynamic) | At compile time (static) |
| Marker | @Override | — |
7. Guided exercise: electronic devices
- Private fields: marca, modelo and porcentajeBateria (0 to 100).
- usarApp(int minutos) drains 1% of battery every 5 minutes.
- cargarBateria(int cantidad) raises the percentage without exceeding 100.
- Extra: lift the shared members into Dispositivo and override encender().
public class Celular extends Dispositivo {
private int porcentajeBateria;
public Celular(String marca, int bateria) {
super(marca);
this.porcentajeBateria =
Math.min(100, Math.max(0, bateria));
}
public void usarApp(int minutos) {
int consumo = minutos / 5;
this.porcentajeBateria =
Math.max(0, porcentajeBateria - consumo);
}
@Override
public void encender() {
System.out.println("Celular encendido");
}
} 8. Takeaways
Each pillar answers a different design question.
Abstraction
What do I model?
Only the fields and actions the domain needs.
Encapsulation
Who may change it?
Only the object itself, validating inside its public methods.
Inheritance
What do I reuse?
The shared base, when the “is-a” relation holds.
Polymorphism
Who answers?
The concrete object in memory, chosen at runtime.