Percursos
/
Crystal
Crystal
/
Exercícios
/
A Máquina de Sumos do Johannes
A Máquina de Sumos do Johannes

A Máquina de Sumos do Johannes

Exercício de aprendizagem

Introdução

As classes são um conceito central na programação orientada a objetos. Em Crystal, tudo é um objeto, cada objeto tem um tipo e pode responder a alguns métodos. As classes são moldes para criar objetos: fornecem valores iniciais para o estado, como variáveis, e implementações de comportamento, como métodos. Os objetos são instâncias de uma classe que guardam todas as variáveis de instância e os seus estados.

Definição de classe

Uma classe define-se com a palavra-chave class, seguida do nome da classe escrito em UpperCamelCase.

class Account
end

Criar uma instância

Para criar uma instância de uma classe, chama o nome da classe com o método new.

class Account
end

account = Account.new

No exemplo acima, a variável account é uma instância da classe Account.

Ao criar uma instância, um método especial chamado initialize funciona como construtor. É chamado quando uma instância é criada. O construtor permite-te definir o estado inicial da instância. O método initialize pode receber argumentos, que são passados ao criar uma instância.

class Account
  def initialize(number)
    5 + number # => 9
  end
end

Account.new(4)
Note

O método initialize não pode devolver um valor manualmente; em vez disso, é o new que devolve a instância acabada de criar.

class Account
  def initialize(number)
    5 + number
  end
end

Account.new(4)
# => #<Account:0x7f5dc33dcea0>

Métodos de instância

Um método de instância é um método que está disponível numa instância de uma classe e pode ser chamado nessa instância. Os métodos de instância definem-se com a palavra-chave def, seguida do nome do método. São definidos dentro da definição da classe.

class Account
  def balance
    100
  end
end

account = Account.new
account.balance # => 100

Variáveis de instância

As variáveis de instância são variáveis que estão disponíveis em todos os métodos da instância. Para acederes a uma variável de instância, precisas de definir um método de instância. Podem ser inicializadas no método initialize. Definem-se com o prefixo @.

class Account
  def initialize
    @balance = 100
  end

  def balance
    @balance
  end
end

account = Account.new
account.balance
# => 100

As variáveis de instância também podem ser definidas dentro da definição da classe.

class Account
  @age = 0
end

Variáveis de instância com inicialização

As variáveis de instância podem ser inicializadas com um argumento passado ao método initialize. Como o Crystal não consegue inferir o tipo do argumento usado durante a inicialização, é preciso especificá-lo. Se quiseres ler mais sobre isto, podes ler: inferência de tipos. Para especificar o tipo da variável, podes usar o símbolo :, seguido do tipo. Por exemplo, se quiseres criar uma variável de instância chamada balance do tipo Int32, podes fazer o seguinte: @balance : Int32. Ou, se quiseres criar uma variável de instância chamada raining do tipo Bool, podes fazer o seguinte: @raining : Bool.

Há várias formas de fazer isto: ou declarar o argumento com o tipo no método initialize e depois atribuir esse argumento à variável de instância, como no exemplo seguinte:

class Account
  def initialize(balance : Int32)
    @balance = balance
  end

  def balance
    @balance
  end
end

account = Account.new(1)
account_2 = Account.new(5)

account.balance
# => 1

account_2.balance
# => 5

Outra forma é declarar o tipo da variável de instância na definição da classe, na forma: @<variable> : <Type>, como no exemplo seguinte:

class Weather

  @raining : Bool

  def initialize(raining)
    @raining = raining
  end

  def raining
    @raining
  end
end

weather = Weather.new(true)
weather.raining
# => true

Modificar variáveis de instância

Os métodos podem modificar variáveis de instância. Esses métodos podem ser chamados na instância da classe. Quando um método modifica uma variável de instância, essa alteração só fica disponível na instância da classe onde o chamaste.

class Account
  def initialize(balance : Int32)
    @balance = balance
  end

  def withdraw(amount)
    @balance -= amount
  end

  def balance
    @balance
  end
end

account = Account.new(10)
account_2 = Account.new(10)
account.balance
# => 10

account_2.balance
# => 10

account.withdraw(5)
account.balance
# => 5

account_2.balance
# => 10

Métodos de classe

Os métodos de classe são métodos definidos para uma classe, mas não para as suas instâncias. Oferecem uma forma de criar métodos que não dependem do estado da instância. Definem-se com a palavra-chave def, seguida de self.<method name>. self é uma referência ao espaço de nomes a partir do qual o self está a ser chamado. Neste caso, refere-se à classe Account. Seria o mesmo que escrever Account., mas self. é a forma preferida.

class Account
  def self.balance
    100
  end
end

Account.balance
# => 100

Instruções

O teu amigo Johannes adora fazer hardware DIY (faz tu mesmo). Acabou de construir uma máquina de sumos e está muito entusiasmado com isso. O objetivo do Johannes é conseguir fazer sumo fresco todas as manhãs.

A máquina de sumos do Johannes tem imensas funcionalidades sofisticadas. Como um sistema de medição incorporado, que te diz quanto sumo está no copo. Também tem um temporizador, que te diz há quanto tempo a máquina está a funcionar.

O Johannes não é o melhor a programar, mas quer fazer um programa para controlar a máquina. Por isso, pediu-te que o ajudasses.

1. Luz de debug

A máquina tem uma luz de debug, é um mecanismo simples: se a máquina tiver corrente, a luz de debug está ligada. O programa só funciona se a luz de debug estiver ligada.

Este método deve ser um método de classe chamado JuiceMaker.

Define o método de classe JuiceMaker.debug_light_on?, que devolve true.

JuiceMaker.debug_light_on?
#=> true

2. Inicializar a máquina

Quando a máquina é ligada, deve criar uma instância de uma classe chamada JuiceMaker. A máquina deve ter um estado inicializado. O estado inicializado deve conter as seguintes informações:

  1. Se a máquina está a funcionar ou não. Isto deve ser sempre false quando a máquina é ligada.
  2. A quantidade de sumo no copo; este será um sensor que mede a quantidade de sumo no copo.

Define o estado inicializado, que recebe a quantidade de sumo no copo como parâmetro, e constrói o estado inicializado. O estado inicializado deve conter uma variável de instância @running, definida como false, e uma variável de instância @fluid, baseada num argumento dado quando a classe é inicializada.

JuiceMaker.new(5)
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=5>

3. Ligar a máquina

A máquina pode ser ligada e desligada. Precisas de definir um método para ligar a máquina. Quando a máquina é ligada, o estado de funcionamento deve ser definido como true.

Define o método JuiceMaker#start, que liga a máquina.

juice_maker = JuiceMaker.new(5)
juice_maker.start

juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=true, @fluid=5>

4. Estado da máquina

A máquina tem de te conseguir dizer qual é o seu estado. Deve devolver true se a máquina estiver a funcionar e false se não estiver a funcionar.

Define o método JuiceMaker#running?, que devolve o estado da máquina.

juice_maker = JuiceMaker.new(5)
juice_maker.start

juice_maker.running?
#=> true

5. Adicionar sumo

A máquina consegue adicionar sumo ao copo. A máquina consegue dizer quanto sumo foi adicionado ao copo. A máquina precisa de ajuda para saber quanto sumo há no copo depois de o sumo ser adicionado.

Define o método JuiceMaker#add_fluid, que recebe a quantidade de sumo adicionada como parâmetro e atualiza a quantidade de sumo no copo.

juice_maker = JuiceMaker.new(5)
juice_maker.add_fluid(5)

juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=10>

6. Desligar a máquina

A máquina pode ser ligada e desligada. Precisas de definir um método para desligar a máquina. Este método só será chamado quando a máquina estiver a funcionar. Quando a máquina é desligada, o estado de funcionamento deve ser definido como false. A máquina também precisa de ajuda para determinar quanto sumo há no copo depois de ser desligada. A máquina consome cinco unidades de sumo por minuto.

Define o método JuiceMaker#stop, que recebe o número de minutos que a máquina esteve a funcionar como parâmetro e devolve a quantidade de sumo no copo depois de a máquina ser desligada.

juice_maker = JuiceMaker.new(5)

juice_maker.start
juice_maker
#=> <JuiceMaker:0x10f0b8 @running=true, @fluid=5>

juice_maker.stop(1)
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=0>
Editar via GitHub A ligação abre numa nova janela ou separador
Crystal Exercism

Estás pronto para começar A Máquina de Sumos do Johannes?

Inscreve-te no Exercism para aprenderes e dominares Crystal com 26 conceitos142 exercícios, e mentoria humana real, tudo grátis.