CSC/ECE 517 Spring 2014/ch1 1w1l m
Design Patterns Involving Closures
Background
Explanation of Closures
Blocks in Ruby
A block is a segment of code that can be used as an argument for a method. These segments of code may have their own initialized variables only able to be referenced locally in the block, much like in a method. Single line blocks are commonly encapsulated in curly braces after a method call, and multi-line blocks are between "do" and "end" statements. A block's code is not executed when it is encountered, but rather after all instances of the yield statement within the method.
=begin
Ruby Code blocks are chunks of code between braces or
between do- end that you can associate with method invocations
=end
def call_block
puts 'Start of method'
# you can call the block using the yield keyword
yield
yield
puts 'End of method'
end
# Code blocks may appear only in the source adjacent to a method call
call_block {puts 'In the block'}
The above code outputs the following:
>ruby p022codeblock.rb
Start of method
In the block
In the block
End of method
>Exit code: 0
So what's a closure?
Very simply, a closure is a function that can use a variable that was valid within the scope that the closure was defined, but need not be in-scope where the closure is called. A quick example is very illustrative.
def closure_builder(message="Default"):
def closure():
# Message is in-scope here
print message
return closure
# Build two functions
default_closure = closure_builder()
custom_closure = closure_builder("Custom")
del closure_builder
# Call the closures you built
default_closure() # Amazingly, prints "Default"
custom_closure() # Amazingly, prints "Custom"
Examples
Decorators
Decorators are an interesting and powerful language feature that can be implemented elegantly with closures.
#!/usr/bin/env python
def decorate(func):
def decorated_func():
print "About to call func"
func()
print "Back from calling func"
return decorated_func
@decorate
def func_to_decorate():
print "In func_to_decorate"
func_to_decorate()
[~517/wiki]$ chmod ug+x decorator.py
[~517/wiki]$ ./decorator.py
About to call func
In func_to_decorate
Back from calling func
Command Pattern
The command Pattern can be implemented using proc objects, which are the closure of an object
In the command pattern, commands for objects to be implemented are queued and can be executed at any time. Arguments are considered passed when the method is called.
count = 0
commands = []
(1..10).each do |i|
commands << proc { count +=i }
end
puts "Count is initially #{count}"
commands.each { |cmd| cmd.call }
puts "Performed all commands. count is #{count}"
Strategy Pattern
The Strategy Pattern allows an algorithms behavior to be determined at runtime. It describes the definition of a family of interchangeable algorithm classes whose functionality is different for identically named methods.
class Fighter
def initialize(&fighting_behavior)
@finish_move = fighting_behavior
end
def finish_opponent
@finish_move.call
end
end
boxer = Fighter.new { puts 'Left hook to the body!' }
boxer.finish_opponent #=> Left hook to the body!
mortal_kombat_warrior = Fighter.new { puts 'Blast him with a lighting bolt' }
mortal_kombat_warrior.finish_opponent #=> Blast him with a lighting bolt
mma = Fighter.new { puts 'Put you to sleep, Good Night!' }
mma.finish_opponent #=> Put you to sleep, Good Night!
lion = Fighter.new { puts 'Bites your head off' }
lion.finish_opponent #=> Bites your head off!
See Also
References
<references />