RubyのProc
Rubyには処理をまとめておけるProcというものがある。
Procを使うには、下記のようにいくつか方法がある。
# 1.1 lambdaを使う
hello = lambda do
puts 'Hello'
end
# 1.2 1行にまとめることも可能
hello = lambda { puts 'Hello' }
# 2.1 Procインスタンスを生成する
world = Proc.new do
puts 'World'
end
# 3. それぞれcallで呼び出すことが可能
hello.call # => Hello
world.call # => World
# 4. 引数を渡すことも可能
hello_text = lambda do |text|
puts "Hello #{text}"
end
hello_text.call('World') # => Hello World
lambdaとProcインスタンスも実は微妙に違うらしい。
その辺りは下記の記事が参考になる。
http://d.hatena.ne.jp/shunsuk/20090101/1230816826
これだけ見ると、関数と何が違うのかわからないが、
Procは関数と組み合わせることによって威力を発揮する。
Procと関数を組み合わせる
Procは関数に渡すことができ、実行できる。
# procを定義
puts_world = lambda { puts 'World' }
def hello(world)
puts 'Hello'
world.call
end
hello puts_world
# Hello
# World
いちいち変数に保存せずに、関数に直接渡すこともできる。
その場合特殊なキーワード「yield」を使用し呼び出すことができる。
これはblockと呼ばれる。
def hello
puts 'Hello'
yield
end
hello do
puts 'World'
end
# Hello
# World
ProcとStrategyデザインパターン
このProcとStrategyデザインパターンは相性がいい。
Strategyデザインパターンとは
例えば、SNSにシェアする機能を作ろうとした時に、まずベースとなるClassを作る。
SNSによってシェアの方法は違うので、それぞれ別にClassを作りベースとなるClassに渡す方法が、Strategyデザインパターンである。
class SNSBase
def initialize(sns)
@sns = sns
@text = 'share to'
end
def share
@sns.share(@text);
end
end
ベースのClassが作成できたら、SNS毎にシェア機能を要したClassを作成する。
class FacebookShare
def share(text)
# facebookにシェアする処理
puts "#{text} facebook"
end
end
class TwitterShare
def share(text)
# twitterにシェアする処理
puts "#{text} twitter"
end
end
実際に使うときにはこんな感じ。
# facebookにシェア
sns = SNSBase.new(FacebookShare.new)
sns.share # => share to facebook
# twitterにシェア
sns = SNSBase.new(TwitterShare.new)
sns.share # => share to twitter
ClassをProcに置き換える
簡単な処理であればClassをProcに置き換えても十分機能する。
その場合BaseのClassを少しいじる必要がある。
class SNSBase
def initialize(&sns)
@sns = sns
@text = 'share to'
end
def share
# initializeで渡ってくるオブジェクトはProcなので、callメソッドに変更
@sns.call(@text);
end
end
実際にこのBaseのClassを使用するのは下記のようなイメージになる。
# facebookにシェア
facebook_share = lambda do |text|
puts "#{text} facebook"
end
sns = SNSBase.new &facebook_share
sns.share # => share to facebook
# twitterにシェア
twitter_share = lambda do |text|
puts "#{text} twitter"
end
sns = SNSBase.new &twitter_share
sns.share # => share to twitter
いちいちClassを各SNSごとに作らなくなるので、さっきよりは少しお手軽になる。
blockを使用する
Procに置き換えても動くように変更したら、もはや変数に格納する必要もなく、Classのインスタンスを作成するときにそのままblockとして処理を渡すことが可能になる。
# facebookにシェア
sns = SNSBase.new do |text|
puts "#{text} facebook"
end
sns.share # => share to facebook
# twitterにシェア
sns = SNSBase.new do |text|
puts "#{text} twitter"
end
sns.share # => share to twitter
お手軽で便利ね〜