C# - Usando o Encapsulamento (revisitado)


Hoje vamos rever o conceito de encapsulamento na linguagem C#.

O que é o encapsulamento ?

O encapsulamento é o processo de ocultar ou esconder os membros de uma classe do acesso exterior usando modificadores de acesso. O encapsulamento também é chamado de ocultação de informação ou information hiding.

O encapsulamento fornece uma maneira de preservar a integridade do estado dos dados. Ao invés de definir campos públicos devemos definir campos de dados privados.

A classe bem encapsulada deve ocultar seus dados e os detalhes de implementação do mundo exterior. Isso é denominado programação caixa preta. Usando o encapsulamento, a implementação do método pode ser alterada pelo autor da classe sem quebrar qualquer código existente fazendo uso dela.

Um modificador de acesso define o escopo e a visibilidade de um membro da classe. A linguagem C# suporta os seguintes modificadores de acesso: 

O modificador de acesso Public

O modificador de acesso Public permite que uma classe exponha suas variáveis de membros e funções de membros a outras funções e objetos.

Qualquer membro público pode ser acessado de fora da classe.

Vejamos o exemplo a seguir:

using static System.Console;
namespace Cshp_Encapsulamento
{
    class Retangulo
    {
        //variáveis membros
        public double comprimento;
        public double largura;
        public double GetArea()
        {
            return comprimento * largura;
        }
        public void Exibir()
        {
            WriteLine("Área do Retângulo\n");
            WriteLine($"Comprimento: {comprimento}");
            WriteLine($"Largura: {largura}");
            WriteLine($"Area: {GetArea()}");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var r = new Retangulo();
            r.comprimento = 2.5;
            r.largura = 1.5;
            r.Exibir();
            ReadLine();
        }
    }
}

Neste código definimos a classe Retangulo contendo dois campos : comprimento e largura que foram declarados como públicos.

Dessa forma eles podem ser acessados diretamente a partir do método Main() usando uma instância r da classe Retangulo.

Os métodos Exibir() e GetArea() também podem acessar esses campos diretamente pois estão na mesma classe.

Aqui o código não esta encapsulado e pode ser alterado por qualquer programa exterior.

O modificador de acesso Private e o ocultamento da informação

Agora vamos usar o código anterior alterando o escopo dos campos comprimento e largura para privados. Fazemos isso usando o modificador de acesso private.

Ao fazer isso você verá que os campos não estão mais acessíveis no método Main() da classe Program, pois o modificador de acesso private permite apenas o acesso local aos campos.

Os campos agora somente podem ser acessados pelos métodos GetArea() e Exibir() da classe Retangulo. Esses métodos são públicos e podem ser acessados no método Main().

Como então acessar os valores de comprimento e largura ?

Podemos declarar um método público chamado InformarValores() e permiter que o valores sejam informados e atribuídos a esses campos:

using static System.Console;
namespace Cshp_Encapsulamento
{
    class Retangulo
    {
        //variáveis membros
        private double comprimento;
        private double largura;
        public double GetArea()
        {
            return comprimento * largura;
        }
        public void Exibir()
        {
            WriteLine("Área do Retângulo\n");
            WriteLine($"Comprimento: {comprimento}");
            WriteLine($"Largura: {largura}");
            WriteLine($"Area: {GetArea()}");
        }
       public void InformarValores()
        {
            WriteLine("Informe o comprimento: ");
            comprimento = Convert.ToDouble(Console.ReadLine());
            WriteLine("Informe a largura : ");
            largura = Convert.ToDouble(Console.ReadLine());
       }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var r = new Retangulo();
            r.InformarValores();
            r.Exibir();
            ReadLine();
        }
    }
}

Executando o projeto iremos obter o seguinte resultado:

Essa implementação é mais robusta pois oculta o valor dos campos largura e comprimento permitindo que eles sejam acessados somente pelo método InformaValores().

Criando propriedades Públicas

Podemos melhorar o código definindo duas propriedades públicas Comprimento e Largura que permitem acessar o valor dos campos comprimento e largura.

Na definição das propriedades podemos incluir uma lógica não permitindo que valores menores que zero sejam incluídos, se isso ocorrer lançamos uma exceção.

Removemos também o método Exibir() da classe Retangulo que estava com a responsabilidade de exibir o resultado e usava para isso recursos da interface do usuário.

Veja como ficou o código :

using System;
using static System.Console;
namespace Cshp_Encapsulamento_Private
{
    class Retangulo
    {
        private double comprimento;
        private double largura;   
        public double Comprimento
        {
            get { return comprimento; }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("O valor do comprimento não pode ser menor que zero");
                }
                else
                {
                    comprimento = value;
                }
            }
        }
        public double Largura
        {
            get { return largura; }
            set
            {
                if (value < 0)
                {
                    throw new Exception("O valor da largura não pode ser menor que zero");
                }
                else
                {
                    largura = value;
                }
            }
        }
        public double GetArea()
        {
            return Comprimento * Largura;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var r = new Retangulo();
            try
            {
                WriteLine("Informe o comprimento: ");
                r.Comprimento = Convert.ToDouble(Console.ReadLine());
                WriteLine("Informe a largura : ");
                r.Largura = Convert.ToDouble(Console.ReadLine());
                WriteLine($"Area do Retangulo: {r.GetArea()}");
            }
            catch (ArgumentException argEx)
            {
                WriteLine($"Erro : {argEx} ");
            }
            ReadLine();
        }
    }
}

Neste código temos o encapsulamento aplicado de forma que o código esta mais aderente às boas práticas. Agora a classe Retangulo tem somente uma responsabilidade: calcular a área do retângulo.

Nota: Podemos tornar a propriedade somente leitura não definindo a propriedade set.

 public double Comprimento
 {
     get { return comprimento; }    
 }

Além disso temos as seguintes vantagens:

Quer outros motivos para preferir usar propriedades públicas ao invés de campos ???

Elementar meu caro Watson...

Pegue o código do exemplo aqui :  Cshp_Encapsulamento.zip

'E Jesus lhe disse: Vai, a tua fé te salvou. E logo viu, e seguiu a Jesus pelo caminho. '
Marcos 10:52

Referências:


José Carlos Macoratti