classCarModel
FEATURES = ["engine", "wheel", "airbag", "alarm", "stereo"]
FEATURES.each do|feature|
define_method("#{feature}_info=") do|info|
instance_variable_set("@#{feature}_info", info)
end
define_method("#{feature}_info") do
instance_variable_get("@#{feature}_info")
end
define_method "feature_price="do|price|
instance_variable_set("@#{feature}_price", price)
end
define_method("#{feature}_price") do
instance_variable_get("@#{feature}_price")
endendend
Method Missing
classMyGhostClassdefmethod_missing(name, *args)
puts "#{name} was called with arguments: #{args.join(',')}"endend
m = MyGhostClass.new
m.awesome_method("one", "two") # => awesome_method was called with arguments: one,two
m.another_method("three", "four") # => another_method was called with arguments: three,four
Métodos dinámicos
User.find_by_email(email)
classUserdefmethod_missing(name, *args)if name =~ /find_by_/# ...endendend
instance_eval vs class_eval
ClassName.instance_eval define un método de clase (asociado a la clase, pero no visible a las instancias).
ClassName.class_eval define un método de instancia (aplica a todas las instancias de ClassName).
class_eval
MyClass.class_eval dodefnum
@num
endend
se comporta exactamente igual que el siguiente código:
classMyClassdefnum
@num
endend
Lambda vs Proc
lambda se comporta como un método, mientras que Proc se comporta como un bloque.
lambda.call()
# => ArgumentError: wrong number of arguments (0 for 1)
proc.call()
# => Hola
Return statement
defprint# esto funciona como esperamos
lambda = lambda { return'lambda' }
puts "lambda = #{lambda.call}"# este `return` va a interrumpir el método `print` y devolver 'proc'
proc = Proc.new { return'proc' }
# esta línea no se va a imprimir por pantalla
puts "proc = #{proc.call}"end
Principios SOLID
Principios SOLID
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
Single responsibility principle
Una clase debe tener solo una razón para cambiar
Ventajas
Codigo más fácil de entender y mantener.
Aumenta la posibilidad de extender el código.
Desventajas
Mayor cantidad de clases.
Funcionalidad distribuida en distintos lugares.
Open/closed principle
Una entidad de software debe quedar abierta para su extensión, pero cerrada para su modificación
Se debe poder cambiar el comportamiento de una clase sin necesidad de modificarla
Ventajas
Diseño claro gracias al polimorfismo.
Código limpio, evitando condiciones innecesarias.
Permite que nuestro código descanse en políticas de alto nivel, dejando los detalles para implementaciones de bajo nivel.
Desventajas
Demanda mayor esfuerzo de previsión, diseño e implementación.
Cuando no disponemos de la suficiente información sobre los requerimientos podemos implementarlo en casos que no lo requerían en un principio.
Liskov substitution principle
Cada clase que hereda de otra puede usarse como su padre sin necesidad de conocer las diferencias entre ellas
Problema:
¿Es un Cuadrado una subclase de Rectángulo?
Soluciones
Push down method / Push down field
Reemplazar herencia con delegación
Interface segregation principle
Muchas interfaces específicas son mejores que una interfaz de propósito general
Los clientes no deberían verse forzados a depender de interfaces que no usan
Interface segregation principle
Dependency inversion principle
El código debe depender de abstracciones, no depender de implementaciones.
Los módulos de alto nivel no deben depender de los módulos de bajo nivel. Ambos deben depender de abstracciones (ej: interfaces)
Las abstracciones no deben depender de detalles. Los detalles deben depender de las abstracciones.
Antipatterns
Duplicated code: varias líneas de código que se repiten a lo largo de diversos métodos en nuestro software.
Feature envy: enviar varios mensajes al mismo objeto desde un mismo método.
Compare to null: comparar variables contra null es un smell de que no estamos manejando objetos sino la posibilidad de la ausencia de los mismos.
Antipatterns
instanceof in conditionals: al preguntar de qué tipo es un objeto dentro de una condición, estamos desperdiciando el polimorfismo.
God class: una clase que tiene demasiado código, por la que pasa gran parte de la lógica de nuestro software.
Too many parameters: la utilización de excesivos parámetros en un mensaje puede indicar la necesidad de crear una nueva clase que agrupe algunos de ellos.