Diseño de software

Encapsulación en OOP: entender el control de acceso de Swift

Al estudiar OOP, escuchas “encapsulación” cientos de veces, pero cuando te preguntan “Entonces, ¿cómo se hace en código?”, puedes quedarte sin palabras. Entiendes el concepto, pero no sabes por dónde empezar a escribir.

5 min de lectura
Imagen de portada de Encapsulación en OOP: entender el control de acceso de Swift

Al estudiar OOP, escuchas “encapsulación” cientos de veces, pero cuando te preguntan “Entonces, ¿cómo se hace en código?”, puedes quedarte sin palabras. Entiendes el concepto, pero no sabes por dónde empezar a escribir.

En resumen, la encapsulación consiste en ocultar los datos internos de un objeto para impedir que se modifiquen libremente desde fuera y permitir el acceso solo mediante rutas definidas. En Swift se implementa con modificadores de acceso.

Hoy veremos en código real los cinco niveles de control de acceso, incluidos private e internal, y entenderemos cómo el ocultamiento de información protege el código.

¿Qué es exactamente la encapsulación?

La encapsulación (Encapsulation) es una de las cuatro características principales de OOP.

En una sola frase:

Agrupar los datos y las funciones que los manipulan, ocultar el interior y exponer solo lo necesario.

¿Por qué ocultarlo?

Piensa en una cuenta bancaria. Sería un desastre que cualquiera pudiera cambiar directamente el saldo por cualquier número.

Los depósitos y retiros deben seguir procedimientos definidos, y reglas como “no puedes retirar más que el saldo” deben cumplirse.

Impedir el acceso directo a los valores internos y abrir solo rutas validadas se denomina ocultamiento de información.

Si la encapsulación es el concepto amplio, el ocultamiento de información es el principio central que lo hace realidad.


Comparación rápida de los cinco niveles de acceso de Swift

Swift divide el alcance de acceso en cinco niveles. Los ordenamos de menor a mayor amplitud.

(Según la sintaxis más reciente de Swift en 2026.)

Modificador de acceso Alcance accesible Uso habitual
private Dentro del bloque de llaves donde se declara Estado interno que realmente quieres ocultar
fileprivate Todo el mismo archivo fuente Tipos colaboradores del mismo archivo
internal Todo el mismo módulo (app/framework) Valor predeterminado; la mayoría del código
public También se puede usar desde otros módulos API pública fuera de la biblioteca
open Permite herencia y redefinición desde otros módulos Puntos de extensión del framework

Hay un punto que debes recordar.

Si no añades nada, internal es el valor predeterminado.

Por eso el código funcionaba dentro de la misma app aunque normalmente no escribieras un modificador de acceso.

También es fácil confundir la diferencia entre public y open. En otro módulo, solo open permite herencia y redefinición. public se puede usar, pero no permite herencia.

Con solo añadir private, el código se vuelve mucho más sólido
Con solo añadir private, el código se vuelve mucho más sólido

Ocultamiento de información real con private

Veamos el ejemplo de una cuenta en código; explicarlo solo con palabras no basta.

Empecemos con un mal ejemplo sin encapsulación.

class BadAccount {
    var balance: Int = 0   // Cualquiera puede modificarlo desde fuera
}

let acc = BadAccount()
acc.balance = -99999      // Incluso se aceptan valores absurdos sin comprobarlos
print(acc.balance)
// Salida: -99999

¿Un saldo de menos 90.000? Las reglas se han desmoronado por completo.

Ahora ocultaremos el estado interno con private y dejaremos abiertas solo las rutas de ingreso y retiro.

class Account {
    private var balance: Int = 0        // Bloquear el acceso externo

    func deposit(_ amount: Int) {
        guard amount > 0 else { return }
        balance += amount
    }

    func withdraw(_ amount: Int) -> Bool {
        guard amount > 0, balance >= amount else { return false }
        balance -= amount
        return true
    }

    var currentBalance: Int { balance }  // Permitir solo la lectura
}

let myAccount = Account()
myAccount.deposit(10000)
print(myAccount.withdraw(30000))  // Saldo insuficiente
// Salida: false

Ahora balance no puede modificarse directamente desde fuera.

Un código como myAccount.balance = -99999 produce un error de compilación.

El dinero solo puede moverse mediante deposit y withdraw, que contienen las reglas de validación.

Ese es el poder del ocultamiento de información: impide desde el principio escribir código que infrinja las reglas.


private(set): permitir la lectura y bloquear solo la escritura

Veamos un caso un poco más práctico.

Es muy habitual querer permitir la lectura externa de un valor, pero impedir que se modifique.

Puedes crear una propiedad calculada independiente, como antes, pero Swift ofrece una opción más limpia.

class ScoreBoard {
    private(set) var score: Int = 0   // Lectura public, Escritura private

    func addPoint() {
        score += 10
    }
}

let board = ScoreBoard()
board.addPoint()
print(board.score)   // La lectura es libre
// Salida: 10
// board.score = 999  // Esta línea produce un error de compilación

Al añadir private(set), la lectura queda abierta y el permiso de escritura se limita al interior.

Como la puntuación solo puede aumentar mediante addPoint(), se evita que la lógica externa del juego la manipule.

Uso mucho esta sintaxis porque no hace falta crear una propiedad calculada.

Desde fuera solo se accede mediante las rutas de ingreso y retiro; el saldo queda bien oculto dentro
Desde fuera solo se accede mediante las rutas de ingreso y retiro; el saldo queda bien oculto dentro

¿Cuándo usar cada modificador?

Estas son las pautas más útiles cuando surgen dudas en el trabajo.

  • Empieza por private. Ampliar el alcance cuando haga falta es más seguro que abrirlo y reducirlo después.
  • El valor predeterminado internal funciona bien en la mayoría de las apps. No hace falta escribirlo todo explícitamente.
  • public·open solo requieren consideración al crear bibliotecas o frameworks para terceros.
  • Usa open solo cuando quieras permitir también la herencia. En caso contrario, public es suficiente.
Situación Decisión
Variable de estado usada solo internamente private
Quieres permitir solo la lectura desde fuera private(set)
Libremente dentro de la misma app internal (predeterminado)
Exponerla públicamente como biblioteca public
Permitir herencia y redefinición externas open

Recuerda esto: el alcance de acceso debe abrirse siempre lo mínimo posible.


Así lo preguntan en una entrevista

P. ¿Cuál es la diferencia entre encapsulación y ocultamiento de información?

La encapsulación es el concepto de diseño que agrupa datos y métodos en un objeto, mientras que el ocultamiento de información es el principio de esconder la implementación interna del exterior. Una respuesta clara es que la encapsulación es el recipiente mayor y el ocultamiento de información se realiza dentro de él mediante modificadores de acceso.

P. ¿Cuál es la diferencia entre public y open en Swift?

Ambos permiten el acceso desde otros módulos, pero solo open permite herencia y redefinición de métodos desde un módulo externo. Las clases public se pueden usar externamente, pero no se pueden heredar. Conviene añadir que open se usa únicamente para abrir puntos de extensión de un framework.


Los modificadores de acceso pueden parecer unas pocas reglas de sintaxis que basta memorizar, pero en realidad entrenan el criterio para diseñar quién puede modificar un valor.

Si escribes tú mismo el ejemplo de la cuenta, lo entenderás enseguida. Te recomiendo empezar añadiendo private en un proyecto pequeño.

Seguir leyendo