「Rubyによるデザインパターン」の読書メモです。
Decoratorパターンについて
既存のオブジェクトに対して簡単に機能を追加するためのパターンです。Decoratorパターンを使うとレイヤ状に機能を積み重ねていくことができ、それぞれの状況でまさに必要なだけの機能をもつオブジェクトを作ることができます。
今回、ファイルに下記の形式で書き出すことができるクラスを作ります。
- プレーンテキスト
- チェックサム付き
- タイムスタンプ付き
- 行番号付き
継承ベースのアプローチ
継承ベースのアプローチでは、あり得るすべての機能の組み合わせを前もって設計時に考えなければならない,ということです。
クラスの数が増えすぎるので、不採用とします。
Decoratorパターンで実装した例
class SimpleWriter
def initialize(path)
@file = File.open(path, 'w')
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
def pos
@file.pos
end
def rewind
@file.rewind
end
def close
@file.close
end
end
class WriterDecorator
def initialize(real_writer)
@real_writer = real_writer
end
def write_line(line)
@real_writer.write_line(line)
end
def pos
@real_writer.pos
end
def rewind
@real_writer.rewind
end
def close
@real_writer.close
end
end
class NumberingWriter < WriterDecorator
def initialize(real_writer)
super(real_writer)
@line_number = 1
end
def write_line(line)
@real_writer.write_line("#{@line_number}: #{line}")
@line_number += 1
end
end
class CheckSummingWriter < WriterDecorator
attr_reader :check_sum
def initialize(real_writer)
@real_writer = real_writer
@check_sum = 0
end
def write_line(line)
line.each_byte {|byte| @check_sum = (@check_sum + byte) % 256}
# check_sum の計算...
@real_writer.write_line("#{line} (checksum: #{@check_sum})")
end
end
class TimeStampingWriter < WriterDecorator
def write_line(line)
@real_writer.write_line("#{Time.new}: #{line}")
end
end
writer = CheckSummingWriter.new(
TimeStampingWriter.new(
NumberingWriter.new(SimpleWriter.new('final.txt'))
)
)
writer.write_line('Hello out there')
出力された final.txt
1: 2019-06-23 13:28:36 +0900: Hello out there (checksum: 164)
Forwardable を使った例
class SimpleWriter
def initialize(path)
@file = File.open(path, 'w')
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
def pos
@file.pos
end
def rewind
@file.rewind
end
def close
@file.close
end
end
出力された final2.txt
2019-06-23 13:34:25 +0900: Hello out there
ラッピングする例
class SimpleWriter
def initialize(path)
@file = File.open(path, 'w')
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
def pos
@file.pos
end
def rewind
@file.rewind
end
def close
@file.close
end
end
w = SimpleWriter.new('final3.txt')
class << w
alias old_write_line write_line
def write_line(line)
old_write_line("#{Time.new}: #{line}")
end
end
w.write_line('write_line')
w.old_write_line('old_write_line')
出力された final3.txt
2019-06-23 13:42:53 +0900: write_line
old_write_line
モジュールを使った例
class SimpleWriter
def initialize(path)
@file = File.open(path, 'w')
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
def pos
@file.pos
end
def rewind
@file.rewind
end
def close
@file.close
end
end
module TimeStampingWriter
def write_line(line)
super("#{Time.new}: #{line}")
end
end
w = SimpleWriter.new('final4.txt')
w.extend(TimeStampingWriter)
w.write_line('hello')
出力された final4.txt
2019-06-23 13:45:02 +0900: hello