Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

26
Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/ Patrones de diseño (en ruby) Ignacio (Nacho) Facello @nachof [email protected]

Transcript of Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

Page 1: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/

Patrones de diseño(en ruby)

Ignacio (Nacho) Facello

@nachof

[email protected]

Page 2: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010
Page 3: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/

Patrones de diseño(en ruby)

Ignacio (Nacho) Facello

@nachof

[email protected]

Page 4: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

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

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

Todo lo que sé de patrones lo aprendí

jugando go

Page 7: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

Joseki

Page 8: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

El mismo joseki...

Page 9: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

… en diferentes contextos.

Page 10: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

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

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

Algunos ejemplos de patrones en Ruby

Page 13: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

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

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

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

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

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

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

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

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

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

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

Algunos usos

● Rails: Model-View-Controller● ActiveRecord::Observer: Observer● Array#sort: Strategy

Page 24: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

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
Page 26: Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

Gracias :-)