Las clases son un concepto central en la programación orientada a objetos. En Crystal, todo es un objeto, cada objeto tiene un tipo y puede responder a algunos métodos. Las clases son planos para crear objetos: proporcionan valores iniciales para el estado, como las variables, e implementaciones del comportamiento, como los métodos. Los objetos son instancias de clase que contienen todas las variables de instancia y los estados.
Una clase se define con la palabra clave class, seguida del nombre de la clase escrito en UpperCamelCase.
class Account
end
Para crear una instancia de una clase, llama al nombre de la clase con el método new.
class Account
end
account = Account.new
En el ejemplo anterior, la variable account es una instancia de la clase Account.
Al crear una instancia, un método especial llamado initialize actúa como constructor.
Se llama cuando se crea una instancia.
El constructor te permite establecer el estado inicial de la instancia.
El método initialize puede recibir argumentos, que se pasan al crear una instancia.
class Account
def initialize(number)
5 + number # => 9
end
end
Account.new(4)
El método initialize no puede devolver un valor manualmente; en su lugar, new devuelve la instancia recién creada.
class Account
def initialize(number)
5 + number
end
end
Account.new(4)
# => #<Account:0x7f5dc33dcea0>
Un método de instancia es un método disponible para una instancia de una clase y se puede llamar sobre esa instancia.
Los métodos de instancia se definen con la palabra clave def, seguida del nombre del método.
Se definen dentro de la definición de la clase.
class Account
def balance
100
end
end
account = Account.new
account.balance # => 100
Las variables de instancia son variables disponibles en todos los métodos de la instancia.
Para acceder a una variable de instancia, necesitas definir un método de instancia.
Se pueden inicializar en el método initialize.
Se definen con el prefijo @.
class Account
def initialize
@balance = 100
end
def balance
@balance
end
end
account = Account.new
account.balance
# => 100
Las variables de instancia también se pueden definir dentro de la definición de la clase.
class Account
@age = 0
end
Las variables de instancia se pueden inicializar con un argumento que se pasa al método initialize.
Como Crystal no puede inferir el tipo del argumento usado durante la inicialización, hay que especificarlo.
Si quieres leer más sobre esto, puedes consultar: inferencia de tipos.
Para especificar el tipo de la variable, puedes usar el símbolo :, seguido del tipo.
Por ejemplo, si quieres crear una variable de instancia llamada balance de tipo Int32, puedes hacer lo siguiente: @balance : Int32.
O si quieres crear una variable de instancia llamada raining de tipo Bool, puedes hacer lo siguiente: @raining : Bool.
Hay varias formas de implementar esto: por ejemplo, declarar el argumento con su tipo en el método initialize y luego asignar la variable de instancia al argumento, como en el ejemplo siguiente:
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
Otra forma es declarar el tipo de la variable de instancia en la definición de la clase con la forma @<variable> : <Type>, como en el ejemplo siguiente:
class Weather
@raining : Bool
def initialize(raining)
@raining = raining
end
def raining
@raining
end
end
weather = Weather.new(true)
weather.raining
# => true
Los métodos pueden modificar variables de instancia. Estos métodos se pueden llamar sobre la instancia de la clase. Cuando un método modifica una variable de instancia, ese cambio solo está disponible en la instancia de la clase sobre la que lo llamaste.
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
Los métodos de clase son métodos que se definen para una clase, pero no para sus instancias.
Ofrecen una forma de crear métodos que no dependen del estado de la instancia.
Se definen con la palabra clave def, seguida de self.<method name>.
self es una referencia al espacio de nombres desde el que se llama a self.
En este caso, se refiere a la clase Account.
Sería lo mismo que escribir Account., pero self. es la forma preferida.
class Account
def self.balance
100
end
end
Account.balance
# => 100
A tu amigo Johannes le encanta el hardware de bricolaje (hazlo tú mismo). Acaba de construir una máquina de zumo y le hace mucha ilusión. El objetivo de Johannes es poder preparar zumo fresco todas las mañanas.
La máquina de zumo de Johannes tiene un montón de funcionalidades sofisticadas. Por ejemplo, un sistema de medición integrado que puede decirte cuánto zumo hay en el vaso. También tiene un temporizador que te dice cuánto tiempo lleva funcionando la máquina.
Johannes no es el mejor programando, pero quiere hacer un programa para controlar la máquina. Por eso te ha pedido que le ayudes.
La máquina tiene una luz de debug, es un mecanismo sencillo: si la máquina recibe corriente, la luz de debug está encendida. El programa solo se ejecutará si la luz de debug está encendida.
Este método debe ser un método de clase llamado JuiceMaker.
Define el método de clase JuiceMaker.debug_light_on? que devuelve true.
JuiceMaker.debug_light_on?
#=> true
Cuando se enciende la máquina, debe crear una instancia de una clase llamada JuiceMaker.
Se supone que la máquina tiene un estado inicializado.
El estado inicializado debe contener la siguiente información:
false cuando se enciende la máquina.Define el estado inicializado, que toma la cantidad de zumo en el vaso como parámetro, y construye el estado inicializado.
El estado inicializado debe albergar una variable de instancia @running que se establece en false, y una variable de instancia @fluid que se basa en un argumento dado cuando se inicializa la clase.
JuiceMaker.new(5)
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=5>
La máquina se puede encender y apagar.
Tienes que definir un método para encender la máquina.
Cuando se enciende la máquina, el estado de funcionamiento debe establecerse en true.
Define el método JuiceMaker#start, que enciende la máquina.
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=true, @fluid=5>
La máquina tiene que poder decirte cuál es su estado.
Debe devolver true si la máquina está funcionando y false si no lo está.
Define el método JuiceMaker#running? que devuelve el estado de la máquina.
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker.running?
#=> true
La máquina puede añadir zumo al vaso. La máquina puede saber cuánto zumo se añade al vaso. La máquina necesita ayuda para saber cuánto zumo hay en el vaso después de añadirlo.
Define el método JuiceMaker#add_fluid, que toma la cantidad de zumo añadida como parámetro y actualiza la cantidad de zumo en el vaso.
juice_maker = JuiceMaker.new(5)
juice_maker.add_fluid(5)
juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=10>
La máquina se puede encender y apagar.
Tienes que definir un método para apagar la máquina
Este método solo se llamará cuando la máquina esté funcionando.
Cuando se apague la máquina, el estado de funcionamiento debe establecerse en false.
La máquina también necesita ayuda para determinar cuánto zumo hay en el vaso después de apagarse.
La máquina consume cinco unidades de zumo por minuto.
Define el método JuiceMaker#stop, que toma el número de minutos que la máquina ha estado funcionando como parámetro y devuelve la cantidad de zumo en el vaso después de apagar la máquina.
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>
Regístrate en Exercism para aprender y dominar Crystal con 26 conceptos142 ejercicios y mentoría humana real, todo gratis.