CodeGym /Cursos /C# SELF /Poniendo en práctica la encapsulación

Poniendo en práctica la encapsulación

C# SELF
Nivel 17 , Lección 4
Disponible

1. Controlamos el acceso

Encapsulación no significa "esconder todo", sino dar acceso controlado.

Muchos que empiezan piensan que encapsulación es simplemente poner todos los campos como private. Es cierto que normalmente los campos son private, pero eso no es toda la historia. La idea principal no es ocultar los datos, sino gestionar el acceso a ellos.

A veces eso significa prohibir totalmente los cambios (por ejemplo, una propiedad get-only). Otras veces — permitir leer y escribir con validación. Otras — permitir leer y modificar solo dentro de la clase (public Type Property { get; private set; }).

La encapsulación te permite crear las "reglas del juego" para tu objeto: definir cómo se puede modificar y garantizar que esos cambios siempre lleven a un estado válido.

En proyectos reales, sobre todo en equipos grandes, sin encapsulación sería un caos. Cualquier desarrollador podría cambiar directamente el estado interno de objetos ajenos, lo que llevaría a errores y conflictos infinitos. La encapsulación pone orden y permite que cada módulo (clase) sea autosuficiente y responsable de sus propios datos.

Esto es una de las piedras angulares de los principios SOLID, en concreto el principio de responsabilidad única (Single Responsibility Principle) y el principio de abierto/cerrado (Open/Closed Principle), de los que aprenderás más adelante. Pero por ahora solo recuerda que la encapsulación hace tu código robusto, flexible y fácil de entender y mantener.


// Objetivo de la encapsulación: una valla invisible alrededor de los datos importantes
// ¡Nadie podrá "liarla" desde fuera por accidente!
La encapsulación protege el objeto de cambios incorrectos

La encapsulación es como poner una valla invisible alrededor de los datos importantes de tu objeto, para que nadie la líe sin querer. No quieres que tu perro de repente tenga una edad negativa — pues la encapsulación se encarga de eso. También ayuda a que la clase sea fácil de usar: otros programadores no tienen que meterse dentro y entender cómo funciona todo, les basta con trabajar con lo que tú decides mostrar. Y lo mejor: si mañana decides cambiar el interior de la clase — por ejemplo, guardar la fecha de nacimiento en vez de la edad — nadie fuera se va a enterar, porque la interfaz sigue igual. ¡Esa es la verdadera magia de la encapsulación!

2. Ventajas de la encapsulación

¿Por qué es tan importante para tus proyectos y tu carrera?

Integridad de los datos (Data Integrity):
La encapsulación te permite asegurarte de que los datos del objeto siempre están en un estado correcto y lógico. Esto reduce mucho los errores en el programa. En entrevistas, cuando te pregunten sobre OOP, si explicas bien cómo la encapsulación ayuda a mantener la integridad de los datos, ¡es un puntazo!

Flexibilidad y facilidad de mantenimiento (Flexibility & Maintainability):
Imagina que al principio guardabas la edad del perro como int Age. Al año el cliente dice: "Oye, ahora necesitamos saber la fecha exacta de nacimiento del perro".

Sin encapsulación: Si Age era public int, en cientos de sitios de tu código habría accesos directos a myDog.Age. Tendrías que cambiar todos esos sitios, pasando de int a DateTime, y la lógica de calcular la edad. ¡Un dolor!

Con encapsulación: Si tenías private int _age; y public int Age { get; set; }, puedes cambiar el campo interno a private DateTime _dateOfBirth; y reescribir la lógica de get y set en la propiedad Age para que calcule la edad a partir de la fecha de nacimiento. El código externo que usa myDog.Age ni se entera del cambio, porque trabaja a través de la interfaz pública Age, no con el campo directamente. A esto se le llama baja acoplamiento (loose coupling).

¿Ves la magia? Cambiamos el "relleno" de la clase, pero la "envoltura" (la interfaz pública) sigue igual.

Depuración más fácil (Easier Debugging):
Si algo va mal con los datos del objeto, con la encapsulación sabes que ha pasado dentro de los métodos de la clase o a través de sus propiedades públicas. El área de búsqueda del bug se reduce a una clase, no a todo el programa.

Mejor diseño de API:
Cuando encapsulas una clase, defines claramente qué forma parte de su "contrato" público (API) y qué es un detalle interno. Esto ayuda a crear interfaces limpias, predecibles y fáciles de entender para tus clases. Cuanto más claro el API, más fácil para otros desarrolladores (¡o para ti en el futuro!) usar tu código.

Seguridad (Security):
Aunque C# no es un lenguaje para sistemas críticos de seguridad como C++, la encapsulación sigue siendo importante. Te permite controlar quién y cómo puede interactuar con tus datos, evitando cambios no deseados o acceso a información confidencial si la hay dentro del objeto.

3. ¿Cómo se logra la encapsulación en C#?

En C#, la encapsulación se consigue principalmente usando:

Modificadores de acceso (private, public y otros):
Hacemos que los campos de la clase sean private para que no se puedan modificar directamente desde fuera. Esto es lo que se llama ocultación de información (information hiding).
Hacemos que los métodos y propiedades sean public para dar acceso controlado a los datos y el comportamiento. Esa es nuestra interfaz pública.

Propiedades (Properties):
Como ya vimos, las propiedades son azúcar sintáctico para los métodos get (lectura) y set (escritura). Nos permiten ocultar el campo, pero dar acceso a través de una fachada pública. Y lo mejor — ¡en el set puedes meter lógica de validación!

Ejemplo: Clase Dog con encapsulación

Primero vamos a escribirlo como NO se debe (sin encapsulación):


public class Dog
{
    public string Name;
    public int Age;

    public void Bark()
    {
        Console.WriteLine($"{Name} dice: ¡Guau!");
    }
}

En esta versión cualquier otra clase puede cambiar el nombre y la edad del perro sin control. Por ejemplo:

Dog dog = new Dog();
dog.Name = "";      // ¡Se puede poner el nombre vacío!
dog.Age = -100;     // Se puede hacer el perro muy "antiguo"

En la vida real eso pasa poco. Pero en el código — mucho, si no piensas en la encapsulación.

Protegemos los datos: hacemos los campos private

Ponemos los campos como privados (private). Así nadie fuera de la clase podrá cambiarlos directamente:


public class Dog
{
    private string _name;
    private int _age;

    public void Bark()
    {
        Console.WriteLine($"{_name} dice: ¡Guau!");
    }
}

Ahora este acceso no es posible:

Dog dog = new Dog();
dog._name = "Rex"; // ¡Error de compilación!

Acceso a los datos mediante propiedades (Properties)

Pero claro, queremos saber el nombre del perro (por ejemplo, para mostrarlo en pantalla), y a veces — cambiarlo, si el perro tiene nuevo dueño o cambia de carácter. ¡Para eso están las propiedades!


public class Dog
{
    private string _name;
    private int _age;

    public string Name
    {
        get { return _name; }
        set
        {
            // Añadimos validación: el nombre no puede estar vacío
            if (string.IsNullOrWhiteSpace(value))
            {
                Console.WriteLine("Error: ¡el nombre no puede estar vacío!");
            }
            else
            {
                _name = value;
            }
        }
    }

    public int Age
    {
        get { return _age; }
        set
        {
            // Un poco de realismo: ¡la edad no puede ser negativa!
            if (value < 0)
            {
                Console.WriteLine("Error: ¡la edad no puede ser negativa!");
            }
            else
            {
                _age = value;
            }
        }
    }

    public void Bark()
    {
        Console.WriteLine($"{_name} dice: ¡Guau!");
    }
}

Ahora los datos están protegidos, pero puedes trabajar con ellos a través de una interfaz controlada:

Dog dog = new Dog();
dog.Name = "Rex";      // ¡Todo ok!
dog.Age = 3;

dog.Name = "";            // Muestra error, el campo no cambia
dog.Age = -1;             // Otra vez error

Propiedades automáticas

Si no necesitas lógica de validación extra, puedes no escribir campos aparte — usa propiedades automáticas:


public class Dog
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void Bark()
    {
        Console.WriteLine($"{Name} dice: ¡Guau!");
    }
}

En este caso Name y Age están "encapsulados" — no puedes acceder a ellos directamente, solo leer y escribir mediante la propiedad.

4. Encapsulamos el comportamiento: solo los métodos necesarios hacia fuera

La encapsulación no es solo sobre datos, ¡también sobre métodos! A veces los métodos de la clase son "engranajes" internos que no hay que mostrar fuera.

Ejemplo:


public class Dog
{
    // Solo para uso interno
    private void WagTail()
    {
        Console.WriteLine("El perro mueve la cola.");
    }

    // Abierto para todos
    public void Bark()
    {
        WagTail(); // llamamos al método oculto dentro de la clase
        Console.WriteLine("¡Guau!");
    }
}

Ahora nadie, salvo el propio perro, podrá hacer que mueva la cola directamente:

Dog dog = new Dog();
dog.WagTail();     // ¡Error! Método privado.
dog.Bark();        // Dentro de Bark se llama a WagTail

Diferencias: campos, métodos, propiedades y su visibilidad

Vamos a resumir:

Parte de la clase ¿Se puede hacer privado? ¿Se puede hacer público? ¿Por qué limitar el acceso?
Campos Sí (¡pero no lo hagas!) Para proteger los datos
Métodos Para ocultar detalles de implementación
Propiedades Controlar lectura/escritura

Recomendación: los campos se hacen private, y solo se exponen mediante propiedades o métodos.

2
Tarea
C# SELF, nivel 17, lección 4
Bloqueada
Validación de datos en propiedades
Validación de datos en propiedades
2
Tarea
C# SELF, nivel 17, lección 4
Bloqueada
Encapsulación con lógica en los métodos
Encapsulación con lógica en los métodos
1
Cuestionario/control
Propiedades (Properties), nivel 17, lección 4
No disponible
Propiedades (Properties)
Propiedades y modificadores de acceso
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION