Upload
nacho-facello
View
1.392
Download
0
Embed Size (px)
Citation preview
Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/
Patrones de diseño(en ruby)
Ignacio (Nacho) Facello
@nachof
Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/
Patrones de diseño(en ruby)
Ignacio (Nacho) Facello
@nachof
Qué son patrones de diseño?
● Un patrón de diseño es una solución general reutilizable a un problema de común ocurrencia en el diseño de software (Wikipedia)
● Concepto originalmente usado en arquitectura (Christopher Alexander)
● Popularizado en el libro Design Patterns: Elements of Reusable Object-Oriented Software, popularmente conocido como GoF (Gang of Four), de Erich Gamma, Richard Helm, Ralph Johnson, y John Vlissides.
Para qué sirven?
● Conocer una solución para un problema dado es útil cuando uno se enfrenta a ese problema.
● Nos dan un lenguaje común.● Suelen resultar en un buen diseño
Todo lo que sé de patrones lo aprendí
jugando go
Joseki
El mismo joseki...
… en diferentes contextos.
Cuando no sirven...
● Que algo sea un patrón no quiere decir que sea adecuado.
● El contexto lo es todo.
Lo importante: elegir la herramienta adecuada
Photo by jannem http://www.flickr.com/photos/jannem/3312116875/
Algunos ejemplos de patrones en Ruby
Singleton
require 'singleton' # From stdlib
class SingletonExample include Singletonend
one = SingletonExample.instancetwo = SingletonExample.instance
puts one == two #=> true
Observer
require 'observer' # From stdlib
class Car include Observable
def initialize @fuel = 100 @speed = 0 end
def run while @fuel > 0 do @speed += 1 @fuel -= 1 changed notify_observers (@speed, @fuel) end endend
class SpeedWarner def initialize(car, speed_limit) @limit = speed_limit car.add_observer(self) end
def update(speed, fuel) puts "Too fast!" if speed > @limit endend
car = Car.newSpeedWarner.new(car, 70)FuelWarner.new(car, 10)
car.run
Staterequire 'state_pattern' # Gem by @dcadenas# http://github.com/dcadenas/state_pattern
class Stop < StatePattern::State def next sleep 3 transition_to (Go) end
def color "Red" endend
class Go < StatePattern::State def next sleep 2 transition_to (Caution) end
def color "Green" endend
class Caution < StatePattern::State def next sleep 1 transition_to (Stop) end
def color "Amber" endend
class TrafficSemaphore include StatePattern set_initial_state Stopend
semaphore = TrafficSemaphore.new
loop do puts semaphore.color semaphore.nextend
Adapterrequire 'forwardable'
class LegacyClassA def some_method(a, b) puts "#{a}, #{b} (old A)" endend
class LegacyClassB def do_something(b, a) puts "#{a}, #{b} (old B)" endend
class AdapterA extend Forwardable
def initialize(adaptee) @adaptee = adaptee end
def_delegator :@adaptee, :some_method, :actionend
class AdapterB def initialize(adaptee) @adaptee = adaptee end
def action(a, b) @adaptee.do_something(b, a) endend
adapted_a = AdapterA.new(LegacyClassA.new)adapted_b = AdapterB.new(LegacyClassB.new)
[adapted_a, adapted_b].each { |adapted| adapted.action("Hello", "World") }
Iterator
class ArrayIterator def initialize(array) @array = array @index = 0 end
def first @index = 0 end
def next @index += 1 end
def current @array [@index] end
def over? @index >= @array.size endend
list = [1,2,3,4]iterator = ArrayIterator.new(list)
while (!iterator.over?) do puts iterator.current iterator.nextend
Iterator
class ArrayIterator def initialize(array) @array = array @index = 0 end
def first @index = 0 end
def next @index += 1 end
def current @array [@index] end
def over? @index >= @array.size endend
list = [1,2,3,4]iterator = ArrayIterator.new(list)
while (!iterator.over?) do puts iterator.current iterator.nextend
Mucho más sencillo...
list = [1,2,3,4]
list.each do |item| puts itemend
Otras formas de iterar
list = [1,2,3,4]
list.each do |item| puts itemend
list.map { |item| item * 2 } #=> [3,4,5,6]
list.any? { |item| item == 2 } #=> true
list.select { |item| item > 2 } #=> [3,4]
list.detect { |item| item > 2 } #=> 3
Strategy
require 'forwardable'
class Caveman extend Forwardable attr_accessor :strategy
def initialize(strategy = DefaultStrategy.new) @strategy = strategy end
def_delegator :@strategy, :survive
def normal_day wake_up survive go_to_sleep end
def wake_up puts "Waking up" end
def go_to_sleep puts "Sleep now" endend
class DefaultStrategy def survive puts "Hide from tigers" endend
class AggressiveStrategy def survive puts "Grab spear, hunt tigers" endend
class ConfusedStrategy def survive puts "Grab tiger, hunt spears" endend
og = Caveman.newog.normal_dayog.strategy = AggressiveStrategy.newog.normal_day
Strategy (con lambdas)
class Caveman attr_accessor :strategy
def initialize(strategy = lambda { puts "Hide from tiger" }) @strategy = strategy end
def normal_day wake_up survive go_to_sleep end
def survive @strategy.call end
def wake_up puts "Waking up" end
def go_to_sleep puts "Sleep now" endend
og = Caveman.newog.normal_dayog.strategy = lambda { puts "Grab spear, hunt tiger" }og.normal_day
Algunos usos
● Rails: Model-View-Controller● ActiveRecord::Observer: Observer● Array#sort: Strategy
Algunos comentarios finales
● Stdlib y gemas son útiles● Memorizarse los patrones y usarlos a cada
oportunidad no ayuda.● Entender sus consecuencias, y su porqué, sí
sirve.● “There may be a dozen different ways to
implement a [given pattern] - it doesn't have to be done exactly like the GoF book or some web page.” Paul Wheaton (http://www.javaranch.com/patterns/)
Gracias :-)