Cargando...

Encapsulación, Herencia y Polimorfismo en C#

Aprende encapsulación, herencia y polimorfismo en C# con ejemplos claros para dominar los principios básicos de la POO.

La Programación Orientada a Objetos (POO / OOP) es un enfoque desarrollado para escribir código reutilizable, mantenible y comprensible. Los tres pilares fundamentales de la POO son:

Cuando estas tres características se utilizan juntas, se puede construir una arquitectura sólida en los proyectos de software. Veamos cada una de ellas por separado.


Encapsulación

La encapsulación oculta la estructura interna de una clase al mundo exterior, exponiendo solo lo necesario. De este modo se evita la manipulación directa de los datos, se reducen los errores y los cambios en la lógica interna no afectan al exterior. En C#, se implementa mediante modificadores de acceso como private, protected, internal y public. Normalmente, los campos se ocultan y el acceso controlado se realiza a través de propiedades o métodos.


public class BankAccount
{
    private decimal _balance; // acceso directo restringido

    public decimal Balance 
    { 
        get => _balance; 
        private set => _balance = value; 
    }

    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("La cantidad debe ser mayor que cero.");
        Balance += amount;
    }

    public void Withdraw(decimal amount)
    {
        if (amount > Balance)
            throw new InvalidOperationException("Fondos insuficientes.");
        Balance -= amount;
    }
}

En este ejemplo, el saldo (_balance) no puede modificarse directamente. El usuario solo puede interactuar con él a través de los métodos Deposit y Withdraw. Esto evita un uso indebido y garantiza la seguridad de los datos.


Herencia

La herencia permite que una clase herede propiedades y comportamientos de otra clase. De esta forma, el código común se centraliza y se vuelve reutilizable. La clase base define los comportamientos generales, mientras que las clases derivadas agregan comportamientos especializados.


public class Animal
{
    public string Name { get; set; } = string.Empty;

    public void Eat()
    {
        Console.WriteLine($"{Name} está comiendo.");
    }
}

public class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine($"{Name} está ladrando.");
    }
}

public class Cat : Animal
{
    public void Meow()
    {
        Console.WriteLine($"{Name} está maullando.");
    }
}

class Program
{
    static void Main()
    {
        Dog d = new Dog { Name = "Rex" };
        d.Eat();  // heredado de Animal
        d.Bark(); // específico de Dog

        Cat c = new Cat { Name = "Misu" };
        c.Eat();  // heredado de Animal
        c.Meow(); // específico de Cat
    }
}

Aquí, tanto Dog como Cat heredan de Animal. El comportamiento común Eat() se escribe una sola vez y está disponible en todas las subclases.


Polimorfismo

El polimorfismo significa que el mismo método puede comportarse de manera diferente según el objeto. Existen dos tipos de polimorfismo:


public class Animal
{
    public string Name { get; set; } = string.Empty;

    public virtual void Speak()
    {
        Console.WriteLine($"{Name} hace un sonido.");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine($"{Name} ladra.");
    }
}

public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine($"{Name} maúlla.");
    }
}

class Program
{
    static void Main()
    {
        Animal a1 = new Dog { Name = "Rex" };
        Animal a2 = new Cat { Name = "Misu" };

        a1.Speak(); // Rex ladra.
        a2.Speak(); // Misu maúlla.
    }
}

La misma llamada a Speak() produce una salida diferente según el tipo de objeto. Esta flexibilidad es una de las características más poderosas de la POO.


Ejemplo: Tipos de libros

Modelemos libros en una aplicación de biblioteca. Las propiedades comunes se definen en la clase Book, mientras que cada subclase agrega su propia información o redefine el método PrintInfo(). Además, las clases Author y Publisher se utilizan para almacenar la información del autor y del editor en objetos separados. Esto demuestra cómo se pueden combinar la herencia y el polimorfismo.


public class Author
{
    public string Name { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
}

public class Publisher
{
    public string Name { get; set; } = string.Empty;
    public string Address { get; set; } = string.Empty;
}

public abstract class Book
{
    public string Title { get; set; } = string.Empty;
    public Author BookAuthor { get; set; } = new Author();
    public Publisher BookPublisher { get; set; } = new Publisher();
    public int Pages { get; set; }
    public string ISBN { get; set; } = string.Empty;
    public int Year { get; set; }

    // Se personalizará en las subclases
    public abstract void PrintInfo();
}

public class ScienceBook : Book
{
    public string Field { get; set; } = string.Empty; // Física, Química, Biología

    public override void PrintInfo()
    {
        Console.WriteLine($"[Libro de Ciencia] {Title} - {BookAuthor.Name}, {Pages} páginas");
        Console.WriteLine($"Campo: {Field}, ISBN: {ISBN}, Editorial: {BookPublisher.Name}");
    }
}

public class HistoryBook : Book
{
    public string Period { get; set; } = string.Empty; // Antigua, Medieval, etc.

    public override void PrintInfo()
    {
        Console.WriteLine($"[Libro de Historia] {Title} - {BookAuthor.Name}, {Pages} páginas");
        Console.WriteLine($"Período: {Period}, ISBN: {ISBN}, Editorial: {BookPublisher.Name}");
    }
}

class Program
{
    static void Main()
    {
        var publisher = new Publisher { Name = "Editorial Conocimiento", Address = "Madrid" };
        var author1 = new Author { Name = "Albert Einstein", Country = "Alemania" };
        var author2 = new Author { Name = "Halil Inalcik", Country = "Turquía" };

        Book b1 = new ScienceBook
        {
            Title = "Teoría de la Relatividad",
            BookAuthor = author1,
            BookPublisher = publisher,
            Pages = 250,
            ISBN = "123-456-789",
            Year = 1920,
            Field = "Física"
        };

        Book b2 = new HistoryBook
        {
            Title = "El Imperio Otomano",
            BookAuthor = author2,
            BookPublisher = publisher,
            Pages = 500,
            ISBN = "987-654-321",
            Year = 1973,
            Period = "Época Otomana"
        };

        b1.PrintInfo();
        Console.WriteLine();
        b2.PrintInfo();
    }
}

Ventajas


TL;DR

  • Encapsulación: Oculta los datos internos y proporciona acceso controlado.
  • Herencia: Las propiedades y comportamientos de la clase base se transmiten a las subclases.
  • Polimorfismo: El mismo método puede comportarse de manera diferente en distintas subclases.

Artículos relacionados