Observer design pattern con Ruby
Pubblicato translation missing: it.datetime.distance_in_words.almost_x_years fa da Andrea
Observer è uno dei design pattern che mi capita di usare più spesso scrivendo applicazioni con Ruby on Rails: quando si ha a che fare con interazioni tra modelli la cosa più sensata da fare è infatti ricorrere ad un observer di ActiveRecord.
Observer è un design pattern tanto frequente e utile che persino la Standard Library di Ruby include un modulo (chiamato non a caso Observable) che ci semplifica la vita ogni qual volta abbiamo bisogno di una classe che al verificarsi di determinate condizioni si occupi di informare altri oggetti.
Ho realizzato un semplice esempio che sfrutta il modulo Observable per realizzare un gioco simile al bingo; si inizia creando la classe che si occuperà di gestire il gioco informando i giocatori sui numeri estratti:
require 'observer' class Bingo include Observable NUMBERS = (1..90).to_a def initialize @remaining_numbers = NUMBERS.sort_by {rand} @players = [] end def start extract until @remaining_numbers.empty? end def extract extracted = @remaining_numbers.pop changed notify_observers(extracted) end end
I passi da seguire qui sono:
- caricare e includere il modulo Observable nella classe
- creare un array (in questo caso @players) che contenga gli oggetti da tenere informati
- ogni qual volta si vuole inviare una notifica si deve usare il metodo changed per dichiarare che c’è stato un cambiamento e successivamente chiamare il metodo notify_observers
Procediamo ora con la creazione della classe Player che si occuperà di ricevere le notifiche in arrivo e agire di conseguenza:
class Player def initialize(name, numbers) @name = name @numbers = numbers end def update(extracted) @numbers.delete(extracted) call_for_victory if @numbers.empty? end def call_for_victory puts "Bingo! #{@name} won this game." exit end end
Qui l’unico passo richiesto è creare il metodo update che verrà chiamato ad ogni notifica.
A questo punto non ci resta che creare qualche instanza delle classi e iniziare il gioco, che si concluderà con la vittoria del primo giocatore che avrà visto chiamare tutti i suoi numeri:
game = Bingo.new fred = Player.new('Fred', [39, 65, 66, 19, 5, 51]) wilma = Player.new('Wilma', [8, 16, 66, 50, 90, 12]) barney = Player.new('Barney', [3, 10, 40, 22, 67, 34]) [fred, wilma, barney].each do |player| game.add_observer player end game.start
Archiviato in Ruby, Design Patterns

