O que é Encapsulamento e como reforçá-lo em sua aplicação usando C#

Neste artigo eu discuto sobre encapsulamento e como implementar seus conceitos em uma aplicação utilizando C#.

Antes de tudo, é importante definir o que é encapsulamento, ainda mais por ser um tema que é recorrente em entrevistas nacionais e internacionais. Já tive que responder ela múltiplas vezes em processos seletivos internacionais que participei.

O que é Encapsulamento

Encapsulamento é um dos pilares da programação orientada a objetos, e se refere ao agrupamento de dados e métodos em uma classe. As ações são realizadas através da invocação de métodos, e o acesso ao estado interno da classe deve ser controlado através de modificadores de acesso.

Para garantir isso, C# oferece modificadores de acesso que podem ser atribuídos a classes, métodos, campos e propriedades. Além disso, ao definir propriedades é possível adicionar lógicas personalizadas quando se acessa ou altera informações contidas em dita propriedades.

De maneira geral, se não existe a necessidade aparente de se expor dados e/ou comportamentos ao exterior, estes devem ter o modificador de acesso mais restrito possível.

Utilizando modificadores de acesso

Os modificadores de acesso em C# são:

  • public: sem restrições no acesso
  • internal: restrito ao assembly onde está contido
  • protected: restrito a class que o contém e a quaisquer classes derivadas
  • protected internal: lógica OU para o internal e protected.
  • private: restrito a classe que o contém
using System;

namespace EnforcingEncapsulation
{
    class Program
    {
        static void Main(string[] args)
        {
            var person = new Person("Luis");
            var employee = new Employee("Dev", "luisdev@email.com");

            // Console.WriteLine(employee.PersonId); Não compila porque PersonId é uma propriedade privada, então é só acessível dentro da classe Person
            // Console.WriteLine(employee.Email); Não compila porque Email é uma propriedade protegida e acessível dentro da classe derivada Employee.
            employee.ShowEmail();
            Console.WriteLine(person.Name);
            Console.WriteLine(employee.CompanyName);
        }
    }

    public class Person
    {
        public Person(string name)
        {
            Name = name;
        }

        private int PersonId { get; set; }
        protected string Email { get; set; }
        public string Name { get; set; }
    }

    public class Employee : Person
    {
        public Employee(string name, string email) : base(name)
        {
            Email = email;
        }

        public string CompanyName = "The Company";

        public void ShowEmail()
        {
            Console.WriteLine(Email);
        }
    }
}

No código-fonte são utilizados os modificadores de acesso public, private e protected.

Utilizando propriedades

Propriedades permitem a adição de lógica ao acessar ou atualizar valores (chamado de accessors), o que não é possível quando se utilizam campos.

Ao se utilizar accessors, você consegue adicionar lógica personalizada que será executada ao se definir ou recuperar o valor.

using System;

namespace EnforcingEncapsulation
{
    class Program
    {
        static void Main(string[] args)
        {
            var employee = new Employee("Luis", 10000.99);

            Console.WriteLine(employee.Salary);

            employee.Salary = "12003.99";

            Console.WriteLine(employee.Salary);

            //employee.Salary = "-0.234"; Throws exception because of the custom SET code. 

            Console.ReadKey();
        }
    }

    public class Person
    {
        public Person(string name)
        {
            Name = name;
        }
        private int PersonId { get; set; }
        protected string Email { get; set; }
        public string Name { get; set; }
    }

    public class Employee : Person
    {
        public Employee(string name, double salary) : base(name)
        {
            _salary = salary;
        }

        public string CompanyName = "The Company";
        private double _salary;
        public string Salary
        {
            get
            {
                return _salary.ToString("#.##");
            }
            set
            {
                var doubleValue = Double.Parse(value);

                _salary = doubleValue < 0 
                    ? throw new ArgumentOutOfRangeException("The Salary value should be positive!") 
                    : doubleValue;
            }
        }
        public void ShowEmail()
        {
            Console.WriteLine(Email);
        }
    }
}

No código-fonte acima foi adicionada uma checagem no valor double convertido a partir da string, permitindo lançar uma exceção antes de atribuir ao campo privado _salary, utilizando o set. Também foi adicionada uma formatação prévia no accessor get.

Conclusão

Neste artigo foi abordado o conceito de encapsulamento, e como ele pode ser explorado em uma aplicação em .NET utilizando os modificadores de acesso e também os accessors get e set de propriedades.

É muito comum esse tema ser perguntado em entrevistas técnicas, então é importante se ter claro seus conceitos, assim como os aspectos técnicos.