Introdução 🚀
Um assunto muito abordado quando estamos começando nossa carreira, é a tal da "lógica proposicional", os famosos if's
else's
que amamos e utilizamos para solucionar problemas simples e complexos. E uma das maiores dificuldades que enfrentamos nessa hora, é como reduzir ao maximo o numero e a complexidade de condicionais.
Felizmente existe a Orientação a Objetos 😁
O que são objetos?💡
Para entendimento geral vamos adotar um objeto, como toda instancia que possui uma classe de definição, hoje a maior parte das linguagens modernas aceitam Orientação a Objetos, mesmo que não seja o paradigma original ou mais usado.
Vamos ao exemplo pratico
Nós fomos contrados para desenvolver um sistema que abriga animais, e a unica coisa que foi solicitado é que seja possivel retornar o tipo do animal e quantas refeições ele precisa, então nós resolvemos implementar a classe Animal
, que é composta pelo atributo kind
, id
e pelo metodo meals
class Animal
attr_reader :kind
def initialize(kind:)
@kind = kind
end
def meals
puts "Needs 2 meals"
end
end
Agora podemos instanciar um objeto
da classe Animal
, e chamar o metodo meals
que irá nos exibir a mensagem Needs 2 meals
dog = Animal.new(kind: "dog")
dog.meals
>>> "Needs 2 meals"
Muito bem! Agora chegou mais uma tarefa, precisamos especializar o metodo meals
para retornar o numero de refeições que esse animal precisa dependendo do kind
dele. Então tivemos a brilhante
ideia de fazer uma condicional utilizando o atributo kind
class Animal
...
def meals
if kind == "dog"
puts "Needs 3 meals"
elsif kind == "bird"
puts "Needs 2 meals"
end
end
end
Muito bem! Nós atendemos nosso problema, porém ja conseguimos sentir uma certa dificuldade com mais animais, vamos precisar de 15 ifs
se continuarmos assim 🤣🤣
Great times are coming!
Bom, já entendemos que objetos tem implementações diferentes, e que eles possuem metodos especificos para cada implementação, sendo assim vamos usar essa capacidade para remover todos
os ifs
desse nosso problema.
Apenas para exemplificar, vamos implementar uma classe chamada Dog
e uma chamada Bird
class Dog
def meals
"Needs 2 meals"
end
end
class Bird
def meals
"Needs 1 meal"
end
end
Agora vamos usar a magia da Composição
, muito parecido com Injeção de dependencia
, para compor essa nova classe Animal
class Animal
attr_reader :kind, :kind_klass
def initialize(kind:, kind_klass:)
@kind = kind
@kind_klass = kind_klass.new
end
def meals
puts kind_klass.meals
end
end
Otimo! Dessa forma não precisamos mais nos preocupar com ifs, cada classe e cada tipo
de animal irá se comportar como quiser, sem a necessidade de tratarmos na classe Animal
já que ela mesmo pode ser varios animais diferentes!
dog = Animal.new(kind: "dog", kind_klass: Dog)
dog.meals
>>> "Needs 2 meals"
Bonus
Bom, e quando não sabemos exatamente qual é o animal? Talvez seu primeiro impulso seja fazer algo parecido com isso:
class Animal
attr_reader :kind, :kind_klass
def initialize(kind:, kind_klass:)
@kind = kind
@kind_klass = kind_klass.new
end
def meals
if kind_klass
puts kind_klass.meals
else
puts "Needs 1 meals"
end
end
end
animal = Animal.new(kind: "Unknown", kind_klass: nil)
animal.meals
>>> "Needs 1 meals"
Resolve nosso problema, mas não estavamos tentando fugir de condicionais? Nós já preparamos o terreno, então vamos apenas nos aproveitar de ter feito uma boa arquitetura!
class DefaultAnimal
def meals
"Needs 1 meals"
end
end
class Animal
attr_reader :kind, :kind_klass
def initialize(kind:, kind_klass: DefaultAnimal)
@kind = kind
@kind_klass = kind_klass.new
end
def meals
kind_klass.meals
end
end
animal = Animal.new(kind: "Unknown")
animal.meals
>>> "Needs 1 meals"
Dessa forma nós já temos um fallback
para caso o usuario não saiba qual animal é, ou caso ainda não exista uma classe implementada pra ele.
Obrigado pela atenção e espero ter ajudado! 👍