Adapter
概要
既存のクラスの出力やインターフェースを必要な形式に変換する
例:
IPhone情報を出力するRenderクラスがある
Renderクラスを使ってAndroid情報を出力したい
- IPhone(Adaptee)
- AndroidAdapter(Adapter)
- Android(Client)
メリット
Adapterを作成すると、Android、IPhoneクラスのどちらも修正しなくて済む
方法1
委譲による実現
IPhoneのオブジェクトをAndroidAdapterに保持させる
class Render
def render(text_object)
@text = text_object.text
@size = text_object.size_cm
@color = text_object.color
printData
end
private
def printData
puts @text
puts "#{@size} cm"
puts @color
end
end
class IPhone
attr_reader :text, :size_cm, :color
def initialize(text, size_cm, color)
@text = text
@size_cm = size_cm
@color = color
end
end
class Android
attr_reader :string, :size_mm, :type
def initialize(string, size_mm, type)
@string = string
@size_mm = size_mm
@type = type
end
end
class AndroidAdapter
def initialize(android)
@android = android
end
def text
@android.string
end
def size_cm
@android.size_mm / 1000
end
def color
@android.type
end
end
iphone = IPhone.new("This is IPhone", 12, "red")
android = Android.new("This is android", 15000, "black")
fixed_android = AndroidAdapter.new(android)
render_object = Render.new
p "---IPhone---"
render_object.render(iphone)
p "---Android---"
render_object.render(fixed_android)
方法2
継承による実現
Androidに新しいインターフェースを記述
android = Android.new("This is android", 15000, "black")
class << android
def color
type
end
def text
string
end
def size_cm
size = size_mm / 1000
"#{size} cm"
end
end
render_object = Render.new
p "---Android---"
p android.text
p android.size_cm
p android.color
Composite
概要
ファイルシステムなどの再帰的なデータ構造を表現を楽にする
要素とそれらをまとめて管理するものが似たようなメソッドを持っていて、どちらも同じように扱いたいとき
例
# 共通メソッドを規定(Component)
class Entry
def get_name; end
def ls(prefix) end
def remove; end
end
# 単純な構成要素、再帰しない(Leaf)
class FileClass < Entry
def initialize(name)
@name = name
end
def get_name
@name
end
def ls(prefix)
puts(prefix + "/" + get_name)
end
def remove
puts "Removed " + @name + " file"
end
end
# 再帰する(Composite)
class DirClass < Entry
def initialize(name)
@name = name
@directory = Array.new
end
def get_name
@name
end
# ディレクトリにディレクトリ/ファイルを追加する
def add(entry)
@directory.push(entry)
end
# ファイル/ディレクトリのパスを返す
def ls(prefix)
puts(prefix + "/" + get_name)
@directory.each do |element|
element.ls(prefix + "/" + @name)
end
end
def remove
@directory.each do |element|
element.remove
end
puts "Removed " + @name + " directory"
end
end
root = DirClass.new("rootDir")
tmp = DirClass.new("tmpDir")
tmp.add(FileClass.new("confFile"))
tmp.add(DirClass.new("dataDir"))
root.add(tmp)
root.ls("")
# /rootDir
# /rootDir/tmpDir
# /rootDir/tmpDir/confFile
# /rootDir/tmpDir/dataDir
root.remove
# Removed confFile file
# Removed dataDir directory
# Removed tmpDir directory
# Removed rootDir directory
Decorator
概要
既存のオブジェクトに対して簡単に機能の追加をする
既存のオブジェクトの変更をしない
例
require 'forwardable'
# ConcreteComponent
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
# Decorator(共通部分)
class WriterDecorator
extend Forwardable
def_delegators :@real_writer, :write_line, :pos, :rewind, :close
def initialize(real_writer)
@real_writer = real_writer
end
end
# Decorator
module NumberingWriter
attr_reader :line_number
def write_line(line)
@line_number = 1 unless @line_number
super("#{@line_number} : #{line}")
@line_number += 1
end
end
# Decorator
module TimeStampingWriter
def write_line(line)
super("#{Time.new} : #{line}")
end
end
f = SimpleWriter.new('88.txt')
f.extend TimeStampingWriter
f.extend NumberingWriter
f.write_line('Hello out there')
f.close
Proxy
概要
プログラム本体のクラスの前にもう一つクラスを咬ませて、データアクセスそのものとそれに付随する処理を分離させる
例
class RealObject
attr_accessor :secret_info
def initialize(secret_info)
@secret_info = secret_info
end
end
class Proxy
attr_accessor :real_object
def initialize(real_object)
@real_object = real_object
end
def secret_info
print "warning use secret_infoz\n"
return @real_object.secret_info
end
end
p = Proxy.new(RealObject.new("secret"))
print p.secret_info