SLIDE 1 / 8

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.

PROCEDURAL calcular() imprimir() guardar() saldo nombre edad global data · high coupling OBJECT-ORIENTED Cuenta - saldo + depositar() Cliente - nombre + getNombre() Banco - cuentas + transferir() encapsulated state · low coupling
KEY DIFFERENCES
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
Object = state (fields) + behaviour (methods) in a single unit responsible for itself.

2. The 4 pillars of OOP

Tap a pillar to jump straight to its slide.

How they fit: abstraction decides what to model, encapsulation protects that model, inheritance extends it and polymorphism makes it interchangeable.

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.

REAL CAR colour upholstery patente bolt count marca scent abstract Vehiculo - patente : String - marca : String - velocidadActual : double + acelerar(double) : void + getVelocidad() : double
Vehiculo.java
// 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;
    }
}
Rule of thumb: if a piece of data drives no decision in the system, it does not belong in the class.

4. Encapsulation

State lives inside the capsule and is private. The only gates are the public methods, which validate every change before applying it.

private double saldo untouchable from outside depositar() retirar() getSaldo()
CuentaBancaria — INTERACTIVE DEMO
getSaldo() 300

Try the public methods: the balance only changes when validation passes.

CuentaBancaria.java
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.

Step 0 / 3 — own members only
Dispositivo - marca : String | - encendido : boolean + encender() : void | + apagar() : void extends extends Telefono - numero : String + marca, encendido (inherited) + encender(), apagar() super(marca); Laptop - pulgadas : int + marca, encendido (inherited) + encender(), apagar() super(marca);
Telefono.java
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");
    }
}
Careful: inherit only when the “is-a” relation truly holds. If it is “has-a”, use composition.

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() };
flota[0] Telefono
flota[1] Laptop
flota[2] Tablet

Telefono → "Screen on, searching for signal"

Laptop → "Booting the operating system"

Tablet → "Reading mode enabled"

One single call, three different answers.

OVERRIDING VS OVERLOADING
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().
Dispositivo - marca, modelo : String + encender() : void Celular - porcentajeBateria : int + usarApp(int) : void Laptop - pulgadas Tablet - lapizIncluido : boolean + encender() : void
Dispositivos.java
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.

01

Abstraction

What do I model?

Only the fields and actions the domain needs.

02

Encapsulation

Who may change it?

Only the object itself, validating inside its public methods.

03

Inheritance

What do I reuse?

The shared base, when the “is-a” relation holds.

04

Polymorphism

Who answers?

The concrete object in memory, chosen at runtime.

Mistake 1 Declaring everything public: with no private state there is no encapsulation, just a struct with methods.
Mistake 2 Inheriting to reuse code when the real relation is “has-a”: that calls for composition.
Mistake 3 Changing the signature while “overriding”: without @Override the JVM treats it as a brand-new method.