Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

RubyでFlyweightパターン

概要

GoFデザインパターンFlyweightパターンについて。
再利用可能なインスタンスを保持しておくことで
処理の軽量化を図ることことを目的とするのがFlyweightパターンです。

Flyweightの語源はボクシングのフライ級。
ボクシングの階級の中でも軽量な階級であることから
処理の軽量化をイメージして名づけられています。

登場人物

Flyweight = 軽量化対象
FlyweightFactory = 軽量化対象の生成工場
Client = 利用者

UML


実装サンプル

サンプル概要

HTMLを生成する処理を想定。
HTMLのタグを組み合わせて、HTML全体を出力します。

全く同じタグを使用する場合は、タグファクトリーによって
プールしてあるタグが利用されます。

登場人物

Flyweight = Tag : HTMLのタグ。軽量化対象役
FlyweightFactory = TagFactory : HTMLのタグを生成する工場。軽量化対象の生成工場役
Client = WebCreator : HTMLのタグを利用して、コンテンツを作る作成者。利用者役

UML


サンプルコード

tag

# encoding: Shift_JIS

=begin rdoc
= Tagクラス
=end
class Tag
  attr_accessor :html
  
  def initialize(tag,attribute_map,has_close)
    @html=""
    if has_close
      @html << "<#{tag}"
      
      unless attribute_map.nil?
        attribute_map.each {|attribute_key,attribute_value|
          @html << " #{attribute_key}='#{attribute_value}'"
        }
      end
      @html << ">"
      @html << "$innerHtml"
      @html << "</#{tag}>"
    else
      @html << "<#{tag} />"
    end
  end
end

tag_factory

# encoding: Shift_JIS
require_relative './tag'

=begin rdoc
= TagFactoryクラス
=end
class TagFactory
  attr_accessor :tag_pool
  
  def initialize()
    @tag_pool = Hash.new
  end
  
  def create_tag(tag_name, attribute_map, has_close)
    tag = @tag_pool[tag_name]
    if tag.nil?
      tag = Tag.new(tag_name, attribute_map, has_close)
      tag_pool[tag_name] = tag
    else
      puts "reuse tag #{tag_name}"
      return tag
    end
  end
end

web_creator

# encoding: Shift_JIS
require_relative './tag'
require_relative './tag_factory'

=begin rdoc
= WebCreatorクラス
=end
class WebCreator
  attr_accessor :tag_factory
  
  def initialize()
    @tag_factory = TagFactory.new
  end

  def create_tag(tag_name, attribute_map=nil, has_close=true)
    return @tag_factory.create_tag(tag_name, attribute_map, has_close)
  end
end

main

# encoding: Shift_JIS
require_relative './web_creator'

web_creator = WebCreator.new
html = web_creator.create_tag "html"
head = web_creator.create_tag "head"
body = web_creator.create_tag "body"
DIV = "div"
contents1 = Hash.new
contents1[:id] = "contents"
contents_tag1 = web_creator.create_tag(DIV,contents1)

div1 = contents_tag1.html.sub('$innerHtml','div1')

hr = web_creator.create_tag("hr",nil,false)

contents2 = Hash.new
contents_tag2 = web_creator.create_tag(DIV,contents1)

div2 = contents_tag2.html.sub('$innerHtml','div2')

inner_body = "#{div1}#{hr.html}#{div2}#{hr.html}"
body_html = body.html.sub('$innerHtml',inner_body)

head_html = head.html.sub('$innerHtml','')
inner_html = "#{head_html}#{body_html}"

puts html.html.sub('$innerHtml',inner_html)
出力結果
reuse tag div
<html><head></head><body><div id='contents'>div1</div><hr /><div id='contents'>div2</div><hr /></body></html>