Orientação a Objetos com Ruby (Parte 2) - Objetos e Classes
Tags: ruby, programming, braziliandevs
Published: 2023-08-22 22:27:03

Fala comiigo!

Dando continuidade à série de Orientação a Objetos com Ruby, nesse post começaremos a falar da parte mais técnica e tentar entender o que é de fato um objeto e como ele se comporta na Programação Orientada a Objetos.

Vamos lá, Objetos...

## O que é Objeto?

Nós podemos podemos pensar em Objetos como a representação de algo do mundo real. Eu sei que pode parecer um pouco aleatório isso, mas a ideia da orientação a objetos é que nós possamos literalmente representar qualquer coisa que esteja presente no nosso mundo, seja tangível ou intangível.

Exemplos disso seriam: um computador, um celular, seu animal de estimação, a casa onde você mora, a cadeira que você senta, tudo.

Poderia inclusive ser você, que enquanto trabalhador exerce a sua profissão todos os dias, ou aquela cafeteria que você vai tomar um cafezinho às vezes. Ou seja, você, seu registro de ponto, a cafeteria, o seu café, a comanda que você recebe, tudo isso pode ser um objeto na Programação Orientada a Objetos (POO).

Pois bem, fica com isso na cuca que a gente precisa adicionar uns detalhes...

### Interação dos Objetos com o Mundo

Vamos fazer uma observação do mundo real. Pensa naquela cafeteria, numa pessoa atendente que está lá todo santo dia trabalhando. Imagine que ela, que aqui vamos chamar de Maria, trabalha 10h por dia contando sábados e domingos, entra às 4:00h e sai apenas às 14:00h.

Que tipo de informações conseguimos extrair fazendo essa observação?
- ~~Provavelmente é uma pessoa trabalhadora super explorada~~
- O nome dessa pessoa é Maria
- A carga horária de trabalho é de 60h semanais
- Horário que ela entra é 4:00h
- Horário que ela sai é às 14:00h

E como essa trabalhadora interage com o mundo real enquanto atendente desta cafeteria?
- Abre comanda
- Anota pedido
- Registra o ponto

Vamos pensar se você foi até esta cafeteria e a Maria, ao te atender, abriu uma comanda de número 5142 para a sua mesa de número 17. Você pediu à Maria um cafezinho pingado e um pão de queijo. Que características conseguimos extrair dessa situação?
- O número da comanda é 5142
- A mesa que ela atende é 17
- Os itens são um café pingado e um pão de queijo
- A pessoa atendente é Maria

E como essa comanda pode "interagir" com o mundo?
- Ela pode receber um novo item
- Um item pode ser removido dela
- Pode ser fechada

Então, pega a visão: **todo objeto tem _características_ e _comportamentos_**.

Se tiver animado, faça esse exercício: olhe à sua volta e anote as _carecterísticas_ e _comportamentos_ você consegue extrair dos objetos que identifica.

## Tá, Objeto foi.. E Classe?
 
Vamos voltar à comanda, onde seu pedido é anotado.

Quando paramos pra pensar, aquele pedaço de papel dividido como uma tabela que tem um número, os itens que você consumiu e o número da sua mesa é apenas uma das possíveis que a Maria vai abrir. Milhares de outras vão existir antes e depois da sua.

Porém, todos estes pedaços de papel tem uma **classificação**, ou uma **Classe**, algo que a define, algo que diz todas as _caraterísticas_ e os _comportamentos_ que esse papel conhecido como **Comanda** precisa ter. Ou seja, a **Classe** é o esqueleto do **Objeto**.

Para que a sua comanda exista com o número 5142, com o seu café pingado e seu pão de queijo, com o número da sua mesa 17 e associada à pessoa atendente Maria, ela precisa de um **molde**, esse molde é a **Classe**.

A partir da **Classe** nós definimos quais _características_ e _comportamentos_ os **Objetos** existirão.

## E o código, heim?! E o Ruby?!

Nos exemplos de código, nós utilizaremos a **Comanda**.

Bem, todo **Objeto surge a partir de uma Classe definida**, então se quisermos representar a **Comanda**, nós precisamos criar uma **Classe** pra ela, e no Ruby seria desta forma:

```ruby
class Comanda
end
```
> A palavra-chave `class` é utilizada para definir uma classe.

Com esta classe criada, se quisermos criar um **Objeto** a partir dela, faremos

```ruby
class Comanda
end

minha_comanda = Comanda.new
```
> Com o `Comanda.new` criamos um objeto Comanda e armazenamos na variável `minha_comanda`. Nós estamos criando somente um objeto, mas não existe um limite que nos impeça de criar mais 2 ou mais 1000 com a mesma classe.

### Adicionando Comportamento na Classe

Como vimos, a **Comanda** possui _comportamentos_ que define as ações que um objeto pode exercer. No Ruby, toda e qualquer comunicação do Objeto com o mundo real ocorre por meio da definição de **Métodos**. E se você veio de outro paradigma de programação, o método é uma _função_ dentro de uma **Classe**.

Vamos pegar como o exemplo o comportamento "ser fechada". Para que a **Comanda** tenha o comportamento de ser fechada, nós vamos criar um método chamado _fechar_ dentro dela desta forma:

```ruby
class Comanda
  def fechar
    puts "Comanda fechada!"
  end
end

...
```

Uma vez que definimos o método _fechar_ na classe, nós podemos chamá-lo no objeto desta forma:

```ruby
class Comanda
  ...
end

minha_comanda = Comanda.new
minha_comanda.fechar
```
> Lembrando que quando definimos o `fechar` ali em cima, nós estamos declarando como o objeto vai se comportar quando este método for chamado. Com isso, você verá que o seguinte texto será impresso na sua tela:

```bash
Comanda fechada!
```

Este foi apenas um exemplo de um método, a ideia é que futuramente ele faça coisas significativas em vez de só imprimir coisas na tela =)

Adicionamos um primeiro comportamento, agora precisamos também adicionar as características.

### Definindo as Características

Na POO, as características de um objeto são conhecidas como **Atributos**.

Uma particularidade do Ruby é que TODO e qualquer atributo de um objeto é privado ao próprio objeto. Um atributo NUNCA será manipulado ou acessado diretamente do mundo exterior ao objeto.

Você deve estar se perguntando, então pra que raios eu vou precisar de um atributo?!?!...

Pois bem, repetindo, ele realmente NUNCA será manipulado ou acessado diretamente do mundo exterior ao objeto, MAS o objeto pode fornecer meios desses atributos serem manipulados se forma indireta. Lembra que eu te falei que "toda e qualquer comunicação do Objeto com o mundo real ocorre por meio da definição de Métodos"? Nós também utilizaremos os métodos para manipular os atributos de um objeto.

Retomando a nossa **Comanda**, nós vimos que ela tem as características como número da comanda, número da mesa, lista de itens e quem é a atendente. E assumiremos que a partir destas características nós vamos definir os atributos _numero_ para o numero da comanda, _mesa_ para o número da mesa, _itens_ para a lista de itens e _atendente_ para o nome da pessoa que te atendeu.

Para que uma **Comanda** possa receber um número, criaremos um método que vai atribuir este valor num atributo _numero_. Para isso, vamos definir este método na classe **Comanda**:

```ruby
class Comanda
  def numero=(numero)
    @numero = numero
  end

  def fechar
  ...
end
```
> No corpo deste método, a variável `@numero` é conhecida como **Variável de Instância** e ela faz parte APENAS do escopo do objeto. É exatamente por este motivo que anteriormente eu disse que um atributo de um objeto nunca será manipulado diretamente fora dele, porque não existe outro recurso seguro para que isso seja feito além de um **Método**.

Estamos criando um método `numero=` (você não leu errado, ele tem um "=" no final do nome) e neste método estamos definindo que ele precisa receber um atributo `numero`. Dentro deste método, estamos pegando o valor que será enviado como parâmetro para `numero` e atribuindo em `@numero`.

Da mesma forma, podemos criar um método para acessar o valor do atributo `@numero`. Com isso, criamos mais um método na **Comanda**:


```ruby
class Comanda
  def numero=(numero)
  ...

  def numero
    @numero
  end

  ...
end

...
```
> No Ruby, apesar da palavra-chave `return` existir, nós a omitimos em diversos casos porque o Ruby sempre retorna a última expressão de um método

Neste método `numero` (que é diferente do método `numero=`), nós estamos retornando o valor do atributo `@numero`.

Para utilizarmos estes dois métodos, não será muito diferente do método `fechar` que usamos na sessão anterior. Podemos chamá-los desta forma:

```ruby
class Comanda
  ...
end

minha_comanda = Comanda.new
minha_comanda.numero = 5421
puts minha_comanda.numero
puts minha_comanda.fechar
```
> Neste caso, estamos chamando o método `numero=` passando como valor `5142` e em seguida chamamos o método `numero` imprimindo o que ele retornou. Por incrível que pareça, o Ruby nos deixa criar um método com um "=" no final do seu nome e chamar desta forma. Esta chamada é a mesma coisa que fazer `minha_comanda.numero=(5421)`

Olhando o resultado deste `puts` da ultima linha, teremos impresso:
```bash
5142
Comanda fechada!
```
> Isso nos certifica que realmente o valor está sendo atribuído em `@numero`.

Para finalizar o papo desse post, vamos criar os mesmos métodos para o atributo _atendente_, _mesa_, _itens_. Os métodos para manipular e ler o número da mesa e os itens ficarão assim:

```ruby
class Comanda
  def numero
  ...

  def atendente=(atendente)
    @atendente = atendente
  end

  def atendente
    @atendente
  end

  def mesa=(mesa)
    @mesa = mesa
  end

  def mesa
    @mesa
  end

  def itens=(itens)
    @itens= itens
  end

  def itens
    @itens
  end

  ...
end

...
```
> Temos um novo método `atendente=` (com "=") para atribuir o nome da pessoa atendente e `atendente` (sem "=") para retornar o valor, que no caso está atribuído na variável de instância `@atendente`. O mesmo está ocorrendo com a mesa e os itens.

Vamos utilizar estes métodos para atribuir valores e imprimi-los. Ficaremos com o código do desta forma:

```ruby
class Comanda
  ...
end

minha_comanda = Comanda.new
minha_comanda.numero = 5421
minha_comanda.atendente = 'Maria'
minha_comanda.mesa = 17
minha_comanda.itens = ['Café pingado', 'Pão de queijo']
puts "Número: #{minha_comanda.numero} | Atendente: #{minha_comanda.atendente} | Mesa: #{minha_comanda.mesa} | Itens: #{minha_comanda.itens.join(',')}"
```
> Com isso, estamos atribuindo `5142` no atributo `@numero`, `"Maria"` no atributo `@atendente`, `17` para `@mesa` e `['Café pingado', 'Pão de queijo']` para `@itens`

Executando este script, será impresso na tela:
```bash
Número: 5142 | Atendente: Maria | Mesa: 17 | Itens: Café pingado,Pão de queijo
```



Com isso a gente termina essa segunda parte dessa série. Ainda tem mais, estamos no começo.

O código que foi feito aqui está neste repositório na branch `parte_02`:
https://github.com/dfmoreto/dev_to-poo_ruby/tree/parte_02

Curtiu? Sinta-se à vontade para fazer correções, comentários ou acréscimos ali em baixo nos comentários =)