WEB系エンジニアの勉強日記

Baby steps to Giant strides!

Decorator Pattern - Design Pattern in Ruby

あるオブジェクトの機能に追加の機能を付け足したい、

さらにいろいろな組み合わせで追加機能を実装したいという時に使えるパターン。

Interface

元の機能を持ったオブジェクト(ConcreteComponent)と追加機能を実装するオブジェクト(Decorator)という登場人物がいて、同じインターフェース(Component)を持つことで、クライアントからは実際にはどのオブジェクトを扱っているかを気にせずに使用できるようになる。

Traditional implementation

DecoratorオブジェクトにConcreteComponentオブジェクトの参照を渡し、追加機能以外の部分をConcreteComponentに委譲する。

Easing the Delegation

forwardableモジュールをextendすることで、delegateの処理を簡潔に書くことができる。

In Ruby

Wrapping Methods

w = SimpleWriter.new('out')

class << w
  alias old_write_line write_line
  def write_line(line)
    old_write_line("#{Time.new}: #{line}")
  end
end

元のメソッドの参照をaliasキーワードで old**に移して、old**をdecorateするメソッドを新たに定義する。

ちょっとした処理を簡単に追加できるが、複数のdecorate処理を買いたい時に、aliasに設定する名前が難しくなってくる。


Decorating with Modules

instance.extend(module) の方法でインタンスにmoduleを設定することで実現する。

簡単なテキストデコレーションを書いてみた。

class TextPrinter
  def output(str)
    print str
  end
end

module TextEmphasizeDecorator
  def output(str)
    print "** "
    print super(str)
    print " **"
  end
end

module TextBracketsDecorator
  def output(str)
    print '('
    super str
    print ')'
  end
end

to = TextPrinter.new
to.extend(TextEmphasizeDecorator)
to.extend(TextBracketsDecorator)

to.output('hoge')