Iniciando com C#—Parte 3—Orientação a Objetos
Já vimos um pouquinho do C# e como ele funciona, seus tipos de dados e estruturas úteis. Agora, entraremos num tópico bem importante e abrangente. É a Orientação a Objetos.
Em nossos programas, realizaremos a implementações de objetos existentes no mundo real. Vamos pegar como exemplo uma conta bancária.
Uma conta bancária possui algumas informações dentro dela, como o número, o nome do titular, o saldo e a data de abertura.
Podemos guardar esses valores em variáveis, como podemos ver a seguir:
Mas um banco não possui apenas a Maria como cliente. E se tivermos que fazer para mais pessoas? Temos que criar novas variáveis e formas de diferenciá-las, começando a ficar complexo.
Para organizarmos isso de forma que não nos confundamos no futuro e consigamos validar os dados de modo a não esquecer de validar alguma variável — que poderia acontecer, devido à imensa quantidade de variáveis que seriam criadas — vamos caracterizar a Conta como uma Classe — representação de algo do mundo real.
A conta, no entanto, possui algumas características — número, nome do titular, saldo e data de abertura. Essas serão as propriedades da Conta.
Utilizei no exemplo acima modificadores de acesso. Mas o que é isso? Eles são importantes para dizer o que conseguimos acessar de fora daquela classe! No caso, as propriedades que estiverem com o modificador public na frente poderão ser alteradas por membros de fora da classe Conta. Vamos ver daqui a pouco sobre eles, mas guardem que a propriedade Saldo está privada!
Até agora, apenas criamos a representação da nossa Conta. No entanto, ela não existe na memória ainda. Quando ela existir, será criado um objeto dela. Com o objeto, podemos fazer operações e ações.
Para criarmos o objeto, iremos instanciá-lo com o uso da palavra new.
Agora temos um objeto da Conta!
E se quisermos modificar as propriedades da nossa primeiraConta? Podemos fazer de duas formas:
Depois da instanciação:
Durante a instanciação (usando chaves):
Vocês repararam que a propriedade Saldo está sublinhada de vermelho? Se tentarmos compilar nossa solução, ela não funcionará. Lembram do porquê? O modificador de acesso dela é private, então eu não consigo acessar como as outras! 🤣 É só mudar o modificador para public que o sublinhado sai!
Dessa forma, as características da nossa primeiraConta não ficam espalhadas, como no início do artigo. Elas ficam em conjunto, dentro de um único objeto da memória.
Com o nosso objeto criado, podemos fazer ações com ele. O que podemos fazer com uma conta? Sacar, verificar o saldo, depositar, transferir… vamos usar os métodos!
Vamos criar o método para efetuar saque, na classe Conta:
Esse método possui o modificador public e poderá ser acessado por outras classes. Após a palavra public, há a palavra double. Ao adicionarmos isso na assinatura de nosso método, significa que ele retornará um valor do tipo double para nós — o saldo! — sim, os métodos podem retornar algo para a gente! (No caso, o nome do método (“Saca”) está sublinhado em vermelho pois não escrevemos o retorno do método ainda. 😝
Vamos adicionar informações neste método?
Aqui, adicionei dois parâmetros: valor e saldo. Quando vamos adicionar um parâmetro em algum método, colocamos primeiro o tipo dele (double) e depois o nome desejado.
No corpo do método, coloquei uma estrutura condicional para verificar se o saldo é maior que o valor. Afinal, não posso sacar um valor que não possui na minha conta. Caso a condição seja verdadeira, é decrementado o valor de saldo.
Obs.: utilizar saldo -= valor é a mesma coisa que saldo = saldo-valor!
Um método foi criado. Bacana! Mas ele não está sendo chamado em lugar nenhum! Como podemos fazer para utilizá-lo?
Sabemos que ele foi adicionado na classe Conta. Fazemos o seguinte:
Como ele pertence à classe Conta, ele está presente no nosso objeto primeiraConta. Chamamos ele passando dentro do parênteses os valores dos parâmetros respectivamente, separados por vírgula. Notem que o segundo parâmetro é primeiraConta.Saldo. Isso quer dizer que estou passando a propriedade de saldo do meu objeto como parâmetro.
Vamos ver como fica executando no console?
Certinho! O saldo anterior de Maria era 2500, conforme colocamos na construção do objeto. Removendo 500, que foi o parâmetro que passamos, fica 2000 na conta!
Dentro da orientação a objetos, há também as Interfaces. Elas são como “contratos” das nossas classes, utilizadas quando queremos que um comportamento seja “forçado” em alguma classe.
Por exemplo, vamos criar a interface IImpostos — por convenção, a nomenclatura de interfaces começa com “I”.
A criação de uma interface é bem parecida com a de uma classe. Trocamos o “class” por “interface”.
No entanto, este nosso “contrato” tem algumas particularidades. A declaração de métodos é feita sem os modificadores de acesso (sempre serão públicos), e os métodos não podem possuem corpo.
Agora, vamos utilizar uma interface na nossa Conta!
Para fazermos o uso de uma interface, utilizamos “: + nome da interface” após o nome da classe.
Como podemos ver, a palavra IImpostos está sublinhada em vermelho. Isso acontece porque não estamos seguindo o contrato que assinamos! Havíamos colocado na interface um método que calcula os impostos, mas não estamos implementando-o na classe Conta — algo que é obrigatório!
Clicando na lâmpada, há uma opção “Implement Interface”. Cliquemos nessa, e o método da interface aparecerá agora na nossa classe, esperando nossa implementação!
Quando criado, é colocado como corpo de forma automática o “throw new NotImplementedException();”. Isso significa que quando esse método for executado, uma exceção será exibida ao usuário, alegando que não foi efetuada nenhuma implementação ou ação a ser realizada.
Tipo Valor x Tipo Referência
Tipo Valor: são armazenados no próprio dado, sendo acessados diretamente. São eles: tipos numéricos, booleanos, char, Date, estruturas e enumerações.
Tipos Referência: dados armazenados na memória Heap (objetos dinâmicos). Aponta para lugares na memória, sendo acessados indiretamente. São eles: String, arrays, classes e delegates.
Ao fazer a alteração do valor de um tipo valor, alteramos de fato o valor dele na memória, pois cada um possui seu próprio espaço.
No entanto, trabalhar com tipo referência é um pouco diferente. Não alteramos o valor daquela propriedade em si. Ao atribuir um objeto a outro, estamos na verdade falando que as duas variáveis irão apontar para o mesmo espaço da memória. Ou seja, alterando uma, todas serão alteradas — por isso do comportamento diferenciado.
Continuamos o assunto na próxima parte! 😁