LoginSignup
35

More than 5 years have passed since last update.

RubyのProcとStrategyデザインパターン

Last updated at Posted at 2013-03-16

RubyのProc

Rubyには処理をまとめておけるProcというものがある。
Procを使うには、下記のようにいくつか方法がある。

proc_sample.rb
# 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_sample3.rb
# procを定義
puts_world = lambda { puts 'World' }

def hello(world)
    puts 'Hello'
    world.call
end

hello puts_world 
# Hello 
# World

いちいち変数に保存せずに、関数に直接渡すこともできる。
その場合特殊なキーワード「yield」を使用し呼び出すことができる。
これはblockと呼ばれる。

proc_sample4.rb
def hello
    puts 'Hello'
    yield
end

hello do
    puts 'World'
end
# Hello 
# World

ProcとStrategyデザインパターン

このProcとStrategyデザインパターンは相性がいい。

Strategyデザインパターンとは

例えば、SNSにシェアする機能を作ろうとした時に、まずベースとなるClassを作る。
SNSによってシェアの方法は違うので、それぞれ別にClassを作りベースとなるClassに渡す方法が、Strategyデザインパターンである。

SNSBase.rb
class SNSBase
    def initialize(sns)
        @sns = sns
        @text = 'share to'
    end

    def share
        @sns.share(@text);
    end
end

ベースのClassが作成できたら、SNS毎にシェア機能を要したClassを作成する。

FacebookShare.rb
class FacebookShare
    def share(text)
        # facebookにシェアする処理
        puts "#{text} facebook"
    end
end
TwitterShare.rb
class TwitterShare
    def share(text)
        # twitterにシェアする処理
        puts "#{text} twitter"
    end
end

実際に使うときにはこんな感じ。

share_sample.rb
# 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を少しいじる必要がある。

SNSBase.rb
class SNSBase
    def initialize(&sns)
        @sns = sns
        @text = 'share to'
    end

    def share
        # initializeで渡ってくるオブジェクトはProcなので、callメソッドに変更
        @sns.call(@text);
    end
end

実際にこのBaseのClassを使用するのは下記のようなイメージになる。

share_sample2.rb
# 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として処理を渡すことが可能になる。

share_sample3.rb
# 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

お手軽で便利ね〜

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35