patrones de diseño (en ruby) — rubyconf uruguay 2010
TRANSCRIPT
![Page 1: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/1.jpg)
Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/
Patrones de diseño(en ruby)
Ignacio (Nacho) Facello
@nachof
![Page 2: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/2.jpg)
![Page 3: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/3.jpg)
Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/
Patrones de diseño(en ruby)
Ignacio (Nacho) Facello
@nachof
![Page 4: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/4.jpg)
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.
![Page 5: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/5.jpg)
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
![Page 6: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/6.jpg)
Todo lo que sé de patrones lo aprendí
jugando go
![Page 7: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/7.jpg)
Joseki
![Page 8: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/8.jpg)
El mismo joseki...
![Page 9: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/9.jpg)
… en diferentes contextos.
![Page 10: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/10.jpg)
Cuando no sirven...
● Que algo sea un patrón no quiere decir que sea adecuado.
● El contexto lo es todo.
![Page 11: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/11.jpg)
Lo importante: elegir la herramienta adecuada
Photo by jannem http://www.flickr.com/photos/jannem/3312116875/
![Page 12: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/12.jpg)
Algunos ejemplos de patrones en Ruby
![Page 13: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/13.jpg)
Singleton
require 'singleton' # From stdlib
class SingletonExample include Singletonend
one = SingletonExample.instancetwo = SingletonExample.instance
puts one == two #=> true
![Page 14: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/14.jpg)
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
![Page 15: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/15.jpg)
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
![Page 16: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/16.jpg)
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") }
![Page 17: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/17.jpg)
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
![Page 18: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/18.jpg)
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
![Page 19: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/19.jpg)
Mucho más sencillo...
list = [1,2,3,4]
list.each do |item| puts itemend
![Page 20: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/20.jpg)
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
![Page 21: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/21.jpg)
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
![Page 22: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/22.jpg)
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
![Page 23: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/23.jpg)
Algunos usos
● Rails: Model-View-Controller● ActiveRecord::Observer: Observer● Array#sort: Strategy
![Page 24: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/24.jpg)
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/)
![Page 25: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/25.jpg)
![Page 26: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010](https://reader033.vdocuments.site/reader033/viewer/2022060200/55983ab71a28ab3b628b47e0/html5/thumbnails/26.jpg)
Gracias :-)