Fala Brab#s! Essa é a segunda parte do post sobre programação orientada a objetos em C#, vamos falar sobre encapsulamento e polimorfismo, que são dois conceitos fundamentais na orientação a objetos. Entretanto, se você ainda não viu o primeiro post, corre lá e dar uma conferida: Programação Orientada a Objetos com C#: Abstração e Herança.
Encapsulamento
O encapsulamento está relacionado à segurança da aplicação. Ele consiste em controlar o acesso às propriedades e métodos de um objeto, definindo quem pode visualizá-los ou alterá-los. Isso é feito utilizando modificadores de acesso, como public
e private
, que restringem a visibilidade de atributos e métodos. Vamos entender o encapsulamento com um exemplo prático.
Exemplo prático: Sistema de Conta Bancária
No post anterior, criamos uma classe Conta
para um sistema bancário, com atributos como proprietario
e saldo
. Todos esses atributos estavam públicos, permitindo que fossem alterados de qualquer parte do código, o que pode comprometer a segurança e consistência dos dados.
Ao aplicar o encapsulamento, podemos tornar esses atributos privados e criar métodos para controlar como os dados são acessados e modificados. Por exemplo, definimos o atributo saldo
como privado e criamos métodos públicos para realizar depósitos e saques, garantindo que essas operações respeitem regras de negócio.
public class Conta { public string NumeroConta { get; set; } public string Proprietario { get; set; } public decimal Saldo { get; private set; } // Definindo a propriedade Saldo como privada para adicionar valores public Conta(string proprietario, decimal saldo) { Proprietario = proprietario; Saldo = saldo; } // Método para realizar depósito public void Deposito(decimal valor) { Saldo += valor; } // Método para realizar saque public void Saque(decimal valor) { if (valor > Saldo) { throw new Exception("Saldo insuficiente"); } Saldo -= valor; } }
Dessa forma, o saldo da conta só pode ser alterado através dos métodos de Deposito
e Saque
, o que garante que o saldo nunca seja alterado diretamente de forma incorreta.
Vamos testar esse código, incluindo os métodos dentro do nosso arquivo Program.cs
class Program { static void Main(string[] args) { var conta = new Conta("Filipe Brito", 100m); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); conta.Deposito(2000); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); conta.Saque(200); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); conta.Saque(3000); } }
Após a execução ele apresentará os seguintes resultados:
Filipe Brito tem 100 de saldo. Filipe Brito tem 2100 de saldo. Filipe Brito tem 1900 de saldo. Unhandled exception. System.Exception: Saldo insuficiente
Perceba que os métodos de Deposito
e Saque
funcionarão corretamente, bem como nossa validação de “Saldo insuficiente”. Também podemos tratar esse erro para que o nosso código fique com um retorno melhor, dessa forma:
class Program { static void Main(string[] args) { try { var conta = new Conta("Filipe Brito", 100m); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); // Filipe Brito tem 100 de saldo. conta.Deposito(2000); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); // Filipe Brito tem 2100 de saldo. conta.Saque(200); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); // Filipe Brito tem 1900 de saldo. conta.Saque(3000); } catch (Exception ex) { Console.WriteLine(ex.Message); // Saldo insuficiente } } }
Polimorfismo
Agora, vamos falar sobre polimorfismo, que é um conceito ligado à capacidade de um método assumir diferentes formas. Isso ocorre principalmente quando uma classe herda outra, mas precisa modificar o comportamento de algum método herdado.
Exemplo prático: Herança e Sobrescrita de Métodos
Vamos adicionar uma classe Poupanca
que herda da classe Conta
. No caso da Poupanca
, queremos que, ao realizar um depósito, o saldo receba um rendimento extra automaticamente. Isso exemplifica o polimorfismo, pois o método de depósito será diferente na classe Poupanca
, mesmo que ela herde o método da classe Conta
.
Para fazermos essa implementação primeiro precisamos adaptar nossa classe Conta
para que o método de depósito seja do tipo virtual
, assim conseguimos sobrescrever esse método em qualquer classe que herde a classe Conta.
public class Conta { public string NumeroConta { get; set; } public string Proprietario { get; set; } public decimal Saldo { get; private set; } public Conta(string proprietario, decimal saldo) { Proprietario = proprietario; Saldo = saldo; } // Método para realizar depósito public virtual void Deposito(decimal valor) { Saldo += valor; } // Método para realizar saque public void Saque(decimal valor) { if (valor > Saldo) { throw new Exception("Saldo insuficiente"); } Saldo -= valor; } }
Agora só precisamos criar a nossa classe Poupanca:
public class Poupanca : Conta { public Poupanca(string proprietario, decimal saldo) : base(proprietario, saldo) { } public override void Deposito(decimal valor) { base.Deposito(valor + 5); // Adiciona 5 BRL de rendimento } }
No exemplo acima, o método Deposito
na classe Poupanca
utiliza o conceito de sobrescrita (override), o que permite modificar o comportamento do método herdado de Conta
.
Quando fazemos um depósito na conta poupança, além de adicionar o valor depositado, ele acrescenta automaticamente 5 BRL de rendimento, criando um comportamento diferenciado em relação à classe Conta
.
Para testar essa nova classe, basta chamar a classe Poupança ao invés da Conta.
class Program { static void Main(string[] args) { try { var conta = new Poupanca("Filipe Brito", 100m); // Incluir nova classe Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); // Filipe Brito tem 100 de saldo. conta.Deposito(2000); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); // Filipe Brito tem 2105 de saldo. conta.Saque(200); Console.WriteLine($"{conta.Proprietario} tem {conta.Saldo} de saldo."); // Filipe Brito tem 1905 de saldo. conta.Saque(3000); } catch (Exception ex) { Console.WriteLine(ex.Message); // Saldo insuficiente } } }
Conclusão
Neste post, vimos dois conceitos importantes da Programação Orientada a Objetos:
- Encapsulamento: Como esconder os atributos de um objeto e oferecer métodos para manipulá-los de forma controlada.
- Polimorfismo: A habilidade de sobrescrever métodos de uma classe base, permitindo comportamentos específicos em classes derivadas.
Esses conceitos são fundamentais para garantir a segurança, flexibilidade e manutenção do código em sistemas orientados a objetos.
Não perca tempo, se você quiser acompanhar o tutorial completo, acesse o vídeo e inscreva-se no canal do BraboDev.
“Desde o princípio, a Palavra estava com Deus. Por meio da Palavra, Deus fez todas as coisas, e nada do que existe foi feito sem ela”
João 1:2