Skip to content

Instantly share code, notes, and snippets.

@metasta
Created June 25, 2018 12:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save metasta/6533b1f7321aa1c61c989cf159630187 to your computer and use it in GitHub Desktop.
Save metasta/6533b1f7321aa1c61c989cf159630187 to your computer and use it in GitHub Desktop.
デザインパターンと Ruby 手習
#!/usr/bin/ruby -Ku
class Aggregate
def iterator
# pass
end
end
class Iterator
def has_next
# pass
end
def next
# pass
end
end
class Book
def initialize(name)
@name = name
end
def get_name
return @name
end
end
class BookShelf
def initialize(maxsize)
@books = Array.new(maxsize)
@last = 0
end
def get_book_at(index)
return @books[index]
end
def append_book(book)
@books[@last] = book
@last += 1
end
def get_length
return @last
end
def iterator
return BookShelfIterator.new(self)
end
end
class BookShelfIterator
def initialize(book_shelf)
@book_shelf = book_shelf
@index = 0
end
def has_next?
if @index < @book_shelf.get_length
return true
else
return false
end
end
def next
@book = @book_shelf.get_book_at(@index)
@index += 1
return @book
end
end
def main
book_shelf = BookShelf.new(4)
book_shelf.append_book(Book.new("Around the World in 80 Days"))
book_shelf.append_book(Book.new("Bible"))
book_shelf.append_book(Book.new("Cinderella"))
book_shelf.append_book(Book.new("Dady-Long-Legs"))
it = book_shelf.iterator
while it.has_next?
book = it.next
puts book.get_name
end
end
main
#!/usr/bin/ruby -Ku
class Banner
def initialize(string)
@string = string
end
def show_with_paren
puts "(#@string)"
end
def show_with_aster
puts "*#@string*"
end
end
class Print
def print_weak
# pass
end
def print_strong
# pass
end
end
class PrintBanner < Banner
def print_weak
show_with_paren
end
def print_strong
show_with_aster
end
end
def main
pr = PrintBanner.new("Hello")
pr.print_weak
pr.print_strong
end
main
#!/usr/bin/ruby -Ku
class Banner
def initialize(string)
@string = string
end
def show_with_paren
puts "(#@string)"
end
def show_with_aster
puts "*#@string*"
end
end
class Print
def print_weak
# pass
end
def print_strong
# pass
end
end
class PrintBanner < Print
def initialize(string)
@banner = Banner.new(string)
end
def print_weak
@banner.show_with_paren
end
def print_strong
@banner.show_with_aster
end
end
def main
pr = PrintBanner.new("Hello")
pr.print_weak
pr.print_strong
end
main
#!/usr/bin/ruby -Ku
require './string-width'
class AbstractDisplay
def open
# pass
end
def put
# pass
end
def close
# pass
end
def display
open
5.times do
put
end
close
end
end
class CharDisplay < AbstractDisplay
def initialize(ch)
@ch = ch
end
def open
print "<<"
end
def put
print @ch
end
def close
puts ">>"
end
end
class StringDisplay < AbstractDisplay
def initialize(string)
@string = string
@width = string.width
end
def open
print_line
end
def put
puts "|#@string|"
end
def close
print_line
end
def print_line
puts "+#{'-' * @width}+"
end
end
def main
d1 = CharDisplay.new("H")
d2 = StringDisplay.new("Hello, world.")
d3 = StringDisplay.new("こんにちは。")
d1.display
d2.display
d3.display
end
main
#!/usr/bin/ruby -Ku
class Product
def use
# pass
end
end
class Factory
def create(owner)
@p = create_product(owner)
register_product(@p)
return @p
end
def create_product(owner)
# pass
end
protected :create_product
def register_product(product)
# pass
end
protected :register_product
end
class IDCard < Product
def initialize(owner)
puts "#{owner}のカードを作ります。"
@owner = owner
end
def use
puts "#{@owner}のカードを使います。"
end
def get_owner
return @owner
end
end
class IDCardFactory < Factory
def initialize()
super
@owners = []
end
def create_product(owner)
return IDCard.new(owner)
end
def register_product(product)
@owners.push(product.get_owner)
end
protected :register_product
def get_owners
return @owners
end
end
def main
factory = IDCardFactory.new
card1 = factory.create("結城浩")
card2 = factory.create("とむら")
card3 = factory.create("佐藤花子")
card1.use
card2.use
card2.use
end
main
#!/usr/bin/ruby -Ku
class Singleton
@@singleton = new
def initialize
puts "インスタンスを生成しました。"
end
def self.get_instance
return @@singleton
end
private_class_method :new
end
def main
puts "Start."
obj1 = Singleton.get_instance
obj2 = Singleton.get_instance
if obj1 == obj2
puts "obj1とobj2は同じインスタンスです。"
else
puts "obj1とobj2は同じインスタンスではありません。"
end
puts "End."
end
main
#!/usr/bin/ruby -Ku
require './string-width'
class Product
def use(s)
# pass
end
def create_clone
# pass
end
end
class Manager
def initialize
@showcase = {}
end
def register(name, proto)
@showcase.store(name, proto)
end
def create(protoname)
pr = @showcase[protoname]
return pr.create_clone
end
end
class MessageBox
def initialize(decochar)
@decochar = decochar
end
def use(s)
length = s.width
puts "#{@decochar * (length + 4)}"
puts "#@decochar #{s} #@decochar"
puts "#{@decochar * (length + 4)}"
end
def create_clone
pr = nil
begin
pr = clone
rescue => e
p e
end
return pr
end
end
class UnderlinePen
def initialize(ulchar)
@ulchar = ulchar
end
def use(s)
length = s.width
puts %{"#{s}"}
puts " #{@ulchar * length}"
end
def create_clone
pr = nil
begin
pr = clone
rescue => e
p e
end
return pr
end
end
def main
manager = Manager.new
upen = UnderlinePen.new("~")
mbox = MessageBox.new("*")
sbox = MessageBox.new("/")
manager.register("strong message", upen)
manager.register("warning box", mbox)
manager.register("slash box", sbox)
p1 = manager.create("strong message")
p1.use("Hello, world.")
p2 = manager.create("warning box")
p2.use("Hello, world.")
p3 = manager.create("slash box")
p3.use("Hello, world.")
end
main
#!/usr/bin/ruby -Ku
class Builder
def make_title(title)
# pass
end
def make_string(string)
# pass
end
def make_items(items)
# pass
end
def close
# pass
end
end
class Director
def initialize(builder)
@builder = builder
end
def construct
@builder.make_title("Greeting")
@builder.make_string("朝から昼にかけて")
@builder.make_items(%w{おはようございます。 こんにちは。})
@builder.make_string("夜に")
@builder.make_items(%w{こんばんは。 おやすみなさい。 さようなら。})
@builder.close
end
end
class TextBuilder < Builder
def initialize
@buffer = ""
end
def make_title(title)
@buffer << "==============================\n"
@buffer << "『#{title}』\n"
@buffer << "\n"
end
def make_string(str)
@buffer << "■#{str}\n"
@buffer << "\n"
end
def make_items(items)
items.each do |i|
@buffer << " ・#{i}\n"
end
@buffer << "\n"
end
def close
@buffer << "==============================\n"
end
def get_result
return @buffer
end
end
class HTMLBuilder < Builder
def make_title(title)
@filename = "#{title}.html"
begin
@writer = open(@filename, "w")
rescue => e
p e
end
@writer.write("<html><head><title>#{title}</title></head><body>")
@writer.write("<h1>#{title}</h1>")
end
def make_string(str)
@writer.write("<p>#{str}</p>")
end
def make_items(items)
@writer.write("<ul>")
items.each do |i|
@writer.write("<li>#{i}</li>")
end
@writer.write("</ul>")
end
def close
@writer.write("</body></html>")
@writer.close
end
def get_result
return @filename
end
end
def main(args)
if args.length != 1
usage
exit(0)
end
if args[0] == "plain"
textbuilder = TextBuilder.new
director = Director.new(textbuilder)
director.construct
result = textbuilder.get_result
puts result
elsif args[0] == "html"
htmlbuilder = HTMLBuilder.new
director = Director.new(htmlbuilder)
director.construct
filename = htmlbuilder.get_result
puts "#{filename} が作成されました。"
else
usage
exit(0)
end
end
def usage
puts "Usage: ruby #$0 plain プレーンテキストで文書作成"
puts "Usage: ruby #$0 html HTMLファイルで文書作成"
end
main(ARGV)
#!/usr/bin/ruby -Ku
class Item
def initialize(caption)
@caption = caption
end
def make_html
# pass
end
end
class Link < Item
def initialize(caption, url)
super(caption)
@url = url
end
end
class Tray < Item
def initialize(caption)
super
@tray = []
end
def add(item)
@tray.push(item)
end
end
class Page
def initialize(title, author)
@title = title
@author = author
@content = []
end
def add(item)
@content.push(item)
end
def output
begin
filename = "#@title.html"
writer = open(filename, "w")
writer.write(self.make_html)
writer.close
puts "#{filename} を作成しました。"
rescue => e
p e
end
end
def make_html
# pass
end
end
class Factory
def self.get_factory(classname)
factory = nil
begin
factory = const_get(classname).new
rescue => e
p e
end
return factory
end
def create_link(caption, url)
# pass
end
def create_tray(caption)
# pass
end
def create_page(title, author)
# pass
end
end
class ListFactory < Factory
def create_link(caption, url)
return ListLink.new(caption, url)
end
def create_tray(caption)
return ListTray.new(caption)
end
def create_page(title, author)
return ListPage.new(title, author)
end
end
class ListLink < Link
def initialize(caption, url)
super
end
def make_html
return %{ <li><a href="#@url">#@caption</a></li>\n}
end
end
class ListTray < Tray
def initialize(caption)
super
end
def make_html
buffer = ""
buffer << "<li>\n"
buffer << "#@caption\n"
buffer << "<ul>\n"
@tray.each do |item|
buffer << item.make_html
end
buffer << "</ul>\n"
buffer << "</li>\n"
return buffer
end
end
class ListPage < Page
def initialize(title, author)
super
end
def make_html
buffer = ""
buffer << "<html><head><title>#@title</title></head>\n"
buffer << "<body>\n"
buffer << "<h1>#@title</h1>\n"
@content.each do |item|
buffer << item.make_html
end
buffer << "</ul>\n"
buffer << "<hr><address>#@author</address>"
buffer << "</body></html>\n"
return buffer
end
end
class TableFactory < Factory
def create_link(caption, url)
return TableLink.new(caption, url)
end
def create_tray(caption)
return TableTray.new(caption)
end
def create_page(title, author)
return TablePage.new(title, author)
end
end
class TableLink < Link
def initialize(caption, url)
super
end
def make_html
return %{<td><a href="#@url">#@caption</a></td>\n}
end
end
class TableTray < Tray
def initialize(caption)
super
end
def make_html
buffer = ""
buffer << "<td>"
buffer << '<table width="100%" border="1"><tr>'
buffer << %{<td bgcolor="#cccccc" align="center" colspan="#{@tray.size}"><b>#@caption</b></td>}
buffer << "</tr>\n"
buffer << "<tr>\n"
@tray.each do |item|
buffer << item.make_html
end
buffer << "</tr></table>"
buffer << "</td>"
return buffer
end
end
class TablePage < Page
def initialize(title, author)
super
end
def make_html
buffer = ""
buffer << "<html><head><title>#@title</title></head>\n"
buffer << "<body>\n"
buffer << "<h1>#@title</h1>\n"
buffer << %{<table width="80%" border="3">\n}
@content.each do |item|
buffer << "<tr>#{item.make_html}</tr>"
end
buffer << "</table>\n"
buffer << "<hr><address>#@author</address>"
buffer << "</body></html>\n"
return buffer
end
end
def main(args)
if args.length != 1
puts "Usage: ruby #$0 Class.Name.Of.ConcreteFactory"
puts "Example 1: ruby #$0 ListFactory"
puts "Example 2: ruby #$0 TableFactory"
exit(0)
end
factory = Factory.get_factory(args[0])
asahi = factory.create_link("朝日新聞", "http://www.asahi.com/")
yomiuri = factory.create_link("読売新聞", "http://www.yomiuri.co.jp/")
us_yahoo = factory.create_link("Yahoo!", "http://www.yahoo.com/")
jp_yahoo = factory.create_link("Yahoo!Japan", "http://www.yahoo.co.jp/")
excite = factory.create_link("Excite", "http://www.excite.com/")
google = factory.create_link("Google", "http://www.google.com/")
traynews = factory.create_tray("新聞")
traynews.add(asahi)
traynews.add(yomiuri)
trayyahoo = factory.create_tray("Yahoo!")
trayyahoo.add(us_yahoo)
trayyahoo.add(jp_yahoo)
traysearch = factory.create_tray("サーチエンジン")
traysearch.add(trayyahoo)
traysearch.add(excite)
traysearch.add(google)
page = factory.create_page("LinkPage", "結城 浩")
page.add(traynews)
page.add(traysearch)
page.output
end
main(ARGV)
#/usr/bin/ruby -Ku
require './string-width'
class Display
def initialize(impl)
@impl = impl
end
def open
@impl.raw_open
end
def print
@impl.raw_print
end
def close
@impl.raw_close
end
def display
open
print
close
end
end
class CountDisplay < Display
def initialize(impl)
super
end
def multi_display(times)
open
times.times do
print
end
close
end
end
class DisplayImpl
def raw_open
# pass
end
def raw_print
# pass
end
def raw_close
# pass
end
end
class StringDisplayImpl < DisplayImpl
def initialize(string)
@string = string
@width = string.width
end
def raw_open
print_line
end
def raw_print
puts "|#@string|"
end
def raw_close
print_line
end
def print_line
puts "+#{'-' * @width}+"
end
end
def main
d1 = Display.new(StringDisplayImpl.new("Hello, Japan."))
d2 = CountDisplay.new(StringDisplayImpl.new("Hello, world."))
d3 = CountDisplay.new(StringDisplayImpl.new("Hello, Universe."))
d1.display
d2.display
d3.display
d3.multi_display(5)
end
main
#!/usr/bin/ruby -Ku
class Hand
HANDVALUE_GUU = 0
HANDVALUE_CHO = 1
HANDVALUE_PAA = 2
attr :handvalue
def initialize(handvalue)
@handvalue = handvalue
end
@@hand = [
Hand.new(HANDVALUE_GUU),
Hand.new(HANDVALUE_CHO),
Hand.new(HANDVALUE_PAA)
]
@@name = %w{グー チョキ パー}
def self.get_hand(handvalue)
return @@hand[handvalue]
end
def stronger_than?(h)
return fight(h) == 1
end
def weaker_than?(h)
return fight(h) == -1
end
def fight(h)
if self == h
return 0
elsif (@handvalue + 1) % 3 == h.handvalue
return 1
else
return -1
end
end
def to_s
return @@name[@handvalue]
end
end
class Strategy
def next_hand
# pass
end
def study(win)
# pass
end
end
class WinningStrategy
def initialize(seed)
srand(seed)
@won = false
end
def next_hand
unless @won
@prev_hand = Hand.get_hand(rand(3))
end
return @prev_hand
end
def study(win)
@won = win
end
end
class ProbStrategy
def initialize(seed)
srand(seed)
@prev_hand_value = 0
@current_hand_value = 0
@history = [
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
]
end
def next_hand
bet = rand(get_sum(@current_hand_value))
handvalue = 0
if bet < @history[@current_hand_value][0]
handvalue = 0
elsif bet < @history[@current_hand_value][0] + @history[@current_hand_value][1]
handvalue = 1
else
handvalue = 2
end
@prev_hand_value = @current_hand_value
@current_hand_value = handvalue
return Hand.get_hand(handvalue)
end
def get_sum(hv)
sum = 0
3.times do |i|
sum += @history[hv][i]
end
return sum
end
def study(win)
if win
@history[@prev_hand_value][@current_hand_value] += 1
else
@history[@prev_hand_value][(@current_hand_value + 1) % 3] += 1
@history[@prev_hand_value][(@current_hand_value + 2) % 3] += 1
end
end
end
class Player
def initialize(name, strategy)
@name = name
@strategy = strategy
@wincount = 0
@losecount = 0
@gamecount = 0
end
def next_hand
return @strategy.next_hand
end
def win
@strategy.study(true)
@wincount += 1
@gamecount += 1
end
def lose
@strategy.study(false)
@losecount += 1
@gamecount += 1
end
def even
@gamecount += 1
end
def to_s
return "[#@name:#@gamecount games, #@wincount win, #@losecount lose]"
end
end
def main(args)
if args.length != 2
puts "Usage: ruby #$0 randomseed1 randomseed2"
puts "Example: ruby #$0 314 15"
exit(0)
end
seed1 = args[0].to_i
seed2 = args[1].to_i
player1 = Player.new("Taro", WinningStrategy.new(seed1))
player2 = Player.new("Hana", ProbStrategy.new(seed2))
10000.times do
next_hand1 = player1.next_hand
next_hand2 = player2.next_hand
if next_hand1.stronger_than?(next_hand2)
puts "Winner:#{player1}"
player1.win
player2.lose
elsif next_hand2.stronger_than?(next_hand1)
puts "Winner:#{player2}"
player1.lose
player2.win
else
puts "Even..."
player1.even
player2.even
end
end
puts "Total result:"
puts player1
puts player2
end
main(ARGV)
#!/usr/bin/ruby -Ku
class Entry
def get_name
# pass
end
def get_size
# pass
end
def add(entry)
raise FileTreatmentException.new
end
def print_list(prefix = "")
# pass
end
def to_s
return get_name + " (#{get_size})"
end
end
class FileEntry < Entry
def initialize(name, size)
@name = name
@size = size
end
def get_name
return @name
end
def get_size
return @size
end
def print_list(prefix = "")
puts "#{prefix}/#{self}"
end
end
class Directory < Entry
def initialize(name)
@directory = []
@name = name
end
def get_name
return @name
end
def get_size
size = 0
@directory.each do |entry|
size += entry.get_size
end
return size
end
def add(entry)
@directory.push(entry)
return self
end
def print_list(prefix = "")
puts "#{prefix}/#{self}"
@directory.each do |entry|
entry.print_list("#{prefix}/#@name")
end
end
end
class FileTreatmentException < Exception
def initialize(msg = "")
super
end
end
def main
begin
puts "Making root entries..."
rootdir = Directory.new("root")
bindir = Directory.new("bin")
tmpdir = Directory.new("tmp")
usrdir = Directory.new("usr")
rootdir.add(bindir)
rootdir.add(tmpdir)
rootdir.add(usrdir)
bindir.add(FileEntry.new("vi", 10000))
bindir.add(FileEntry.new("latex", 20000))
rootdir.print_list
puts ""
puts "Making user entries..."
yuki = Directory.new("yuki")
hanako = Directory.new("hanako")
tomura = Directory.new("tomura")
usrdir.add(yuki)
usrdir.add(hanako)
usrdir.add(tomura)
yuki.add(FileEntry.new("diary.html", 100))
yuki.add(FileEntry.new("Composite.java", 200))
hanako.add(FileEntry.new("memo.tex", 300))
tomura.add(FileEntry.new("game.doc", 400))
tomura.add(FileEntry.new("junk.mail", 500))
rootdir.print_list
rescue => e
p e
end
end
main
#!/usr/bin/ruby -Ku
require './string-width'
class Display
def get_columns
# pass
end
def get_rows
# pass
end
def get_row_text(row)
# pass
end
def show
get_rows.times do |i|
puts get_row_text(i)
end
end
end
class StringDisplay < Display
def initialize(string)
@string = string
end
def get_columns
return @string.width
end
def get_rows
return 1
end
def get_row_text(row)
if row == 0
return @string
else
return nil
end
end
end
class Border < Display
def initialize(display)
@display = display
end
end
class SideBorder < Border
def initialize(display, ch)
super(display)
@border_char = ch
end
def get_columns
return 1 + @display.get_columns + 1
end
def get_rows
return @display.get_rows
end
def get_row_text(row)
return "#@border_char#{@display.get_row_text(row)}#@border_char"
end
end
class FullBorder < Border
def initialize(display)
super
end
def get_columns
return 1 + @display.get_columns + 1
end
def get_rows
return 1 + @display.get_rows + 1
end
def get_row_text(row)
if row == 0
return "+#{make_line('-', @display.get_columns)}+"
elsif row == @display.get_rows + 1
return "+#{make_line('-', @display.get_columns)}+"
else
return "|#{@display.get_row_text(row - 1)}|"
end
end
def make_line(ch, count)
return ch * count
end
end
def main
b1 = StringDisplay.new("Hello, world.")
b2 = SideBorder.new(b1, "#")
b3 = FullBorder.new(b2)
b1.show
b2.show
b3.show
b4 = (
SideBorder.new(
FullBorder.new(
FullBorder.new(
SideBorder.new(
FullBorder.new(
StringDisplay.new("こんにちは。")
),
"*"
)
)
),
"/"
)
)
b4.show
end
main
#!/usr/bin/ruby -Ku
class Visitor
def visit(entry)
# pass
end
end
class Element
def accept(v)
# pass
end
end
class Entry < Element
def get_name
# pass
end
def get_size
# pass
end
def add(entry)
raise FileTreatmentException.new
end
def to_s
return "#{get_name} (#{get_size})"
end
end
class FileEntry < Entry
def initialize(name, size)
@name = name
@size = size
end
def get_name
return @name
end
def get_size
return @size
end
def accept(v)
v.visit(self)
end
end
class Directory < Entry
def initialize(name)
@name = name
@dir = []
end
def get_name
return @name
end
def get_size
size = 0
@dir.each do |entry|
size += entry.get_size
end
return size
end
def add(entry)
@dir.push(entry)
return self
end
def each
@dir.each do |d|
yield(d)
end
end
def accept(v)
v.visit(self)
end
end
class ListVisitor < Visitor
@currentdir = ""
def visit_file(file)
puts "#@currentdir/#{file}"
end
def visit_directory(directory)
puts "#@currentdir/#{directory}"
savedir = @currentdir
@currentdir = "#@currentdir/#{directory.get_name}"
directory.each do |entry|
entry.accept(self)
end
end
def visit(entry)
if entry.instance_of?(FileEntry)
visit_file(entry)
elsif entry.instance_of?(Directory)
visit_directory(entry)
else
p entry.class
end
end
end
class FileTreatmentException < Exception
def initialize(msg = "")
super
end
end
def main
begin
puts "Making root entries..."
rootdir = Directory.new("root")
bindir = Directory.new("bin")
tmpdir = Directory.new("tmp")
usrdir = Directory.new("usr")
rootdir.add(bindir)
rootdir.add(tmpdir)
rootdir.add(usrdir)
bindir.add(FileEntry.new("vi", 10000))
bindir.add(FileEntry.new("latex", 20000))
rootdir.accept(ListVisitor.new)
puts ""
puts "Making user entries..."
yuki = Directory.new("yuki")
hanako = Directory.new("hanako")
tomura = Directory.new("tomura")
usrdir.add(yuki)
usrdir.add(hanako)
usrdir.add(tomura)
yuki.add(FileEntry.new("diary.html", 100))
yuki.add(FileEntry.new("Composite.java", 200))
hanako.add(FileEntry.new("memo.tex", 300))
tomura.add(FileEntry.new("game.doc", 400))
tomura.add(FileEntry.new("junk.mail", 500))
rootdir.accept(ListVisitor.new)
rescue => e
p e
end
end
main
#!/usr/bin/ruby -Ku
class Trouble
def initialize(number)
@number = number
end
def get_number
return @number
end
def to_s
return "[Trouble #@number]"
end
end
class Support
def initialize(name)
@name = name
end
def set_next(next_support)
@next = next_support
return next_support
end
def support(trouble)
if resolve(trouble)
done(trouble)
elsif @next != nil
@next.support(trouble)
else
fail(trouble)
end
end
def to_s
return "[#@name]"
end
def resolve(trouble)
# pass
end
def done(trouble)
puts "#{trouble} is resolved by #{self}."
end
def fail(trouble)
puts "#{trouble} cannot be resolved."
end
end
class NoSupport < Support
def initialize(name)
super
end
def resolve(trouble)
return false
end
end
class LimitSupport < Support
def initialize(name, limit)
super(name)
@limit = limit
end
def resolve(trouble)
if trouble.get_number < @limit
return true
else
return false
end
end
end
class OddSupport < Support
def initialize(name)
super
end
def resolve(trouble)
if trouble.get_number % 2 == 1
return true
else
return false
end
end
end
class SpecialSupport < Support
def initialize(name, number)
super(name)
@number = number
end
def resolve(trouble)
if trouble.get_number == @number
return true
else
return false
end
end
end
def main
alice = NoSupport.new("Alice")
bob = LimitSupport.new("Bob", 100)
charlie = SpecialSupport.new("Charlie", 429)
diana = LimitSupport.new("Diana", 200)
elmo = OddSupport.new("Elmo")
fred = LimitSupport.new("Fred", 300)
alice.set_next(bob).set_next(charlie).set_next(diana).set_next(elmo).set_next(fred)
0.step(500, 33) do |i|
alice.support(Trouble.new(i))
end
end
main
#!/usr/bin/ruby -Ku
class Properties
def initialize
@hash = {}
end
def load(filename)
IO.foreach(filename) do |line|
@hash.store(*line.chomp.split("=", 2))
end
end
def get_property(key)
return @hash[key]
end
def show
@hash.each do |k, v|
p "#{k} #{v}"
end
end
end
class Database
private_class_method :new
def self.get_properties(dbname)
filename = "#{dbname}.txt"
prop = Properties.new
begin
prop.load(filename)
rescue => e
puts "Warning: #{filename} is not found."
p e
end
return prop
end
end
class HTMLWriter
def initialize(writer)
@writer = writer
end
def title(title)
@writer.write("<html>")
@writer.write("<head>")
@writer.write("<title>#{title}</title>")
@writer.write("</head>")
@writer.write("<body>\n")
@writer.write("<h1>#{title}</h1>\n")
end
def paragraph(msg)
@writer.write("<p>#{msg}</p>\n")
end
def link(href, caption)
paragraph(%{<a href="#{href}">#{caption}</a>})
end
def mailto(mailaddr, username)
link("mailto:#{mailaddr}", username)
end
def close
@writer.write("</body>")
@writer.write("</html>\n")
@writer.close
end
end
class PageMaker
private_class_method :new
def self.make_welcome_page(mailaddr, filename)
begin
mailprop = Database.get_properties("maildata")
username = mailprop.get_property(mailaddr)
writer = HTMLWriter.new(open(filename, "w"))
writer.title("Welcome to #{username}'s page!")
writer.paragraph("#{username}のページへようこそ。")
writer.paragraph("メールまっていますね。")
writer.mailto(mailaddr, username)
writer.close
puts "#{filename} is created for #{mailaddr} (#{username})"
rescue => e
p e
end
end
end
def main
PageMaker.make_welcome_page("hyuki@hyuki.com", "welcome.html")
end
main
#!/usr/bin/ruby -Ku
#!/usr/bin/ruby -Ku
class Observer
def update(generator)
# pass
end
end
class NumberGenerator
def initialize
@observers = []
end
def add_observer(observer)
@observers.push(observer)
end
def delete_observer(observer)
@observers.delete(observer)
end
def notify_observers
@observers.each do |o|
o.update(self)
end
end
def get_number
# pass
end
def execute
# pass
end
end
class RandomNumberGenerator < NumberGenerator
def get_number
return @number
end
def execute
20.times do
@number = rand(50)
notify_observers
end
end
end
class DigitObserver
def update(generator)
puts "DigitObserver:#{generator.get_number}"
begin
sleep 0.1
rescue => e
# pass
end
end
end
class GraphObserver
def update(generator)
puts "GraphObserver:#{'*' * generator.get_number}"
begin
sleep 0.1
rescue => e
# pass
end
end
end
def main
generator = RandomNumberGenerator.new
observer1 = DigitObserver.new
observer2 = GraphObserver.new
generator.add_observer(observer1)
generator.add_observer(observer2)
generator.execute
end
main
#!/usr/bin/ruby -Ku
class Memento
def initialize(money)
@money = money
@fruits = []
end
def get_money
return @money
end
def add_fruit(fruit)
@fruits.push(fruit)
end
def get_fruits
return @fruits
end
end
class Gamer
def initialize(money)
@money = money
@fruits = []
@fruitsname = %w{リンゴ ぶどう バナナ みかん}
end
def get_money
return @money
end
def bet
dice = rand(6) + 1
if dice == 1
@money += 100
puts "所持金が増えました。"
elsif dice == 2
@money /= 2
puts "所持金が半分になりました。"
elsif dice == 6
f = get_fruit
puts "フルーツ(#{f})をもらいました。"
@fruits.push(f)
else
puts "何も起こりませんでした。"
end
end
def create_memento
m = Memento.new(@money)
@fruits.each do |f|
if f.match(/^おいしい/)
m.add_fruit(f)
end
end
return m
end
def restore_memento(memento)
@money = memento.get_money
@fruits = memento.get_fruits
end
def to_s
return "[money = #@money, fruits = [#{@fruits.join(', ')}]]"
end
def get_fruit
prefix = (rand(2) == 1) ? "おいしい" : ""
return "#{prefix}#{@fruitsname[rand(@fruitsname.length)]}"
end
end
def main
gamer = Gamer.new(100)
memento = gamer.create_memento
100.times do |i|
puts "==== #{i}"
puts "現状:#{gamer}"
gamer.bet
puts "所持金は#{gamer.get_money}円になりました。"
if gamer.get_money > memento.get_money
puts " (だいぶ増えたので、現在の状態を保存しておこう)"
memento = gamer.create_memento
elsif gamer.get_money < memento.get_money / 2
puts " (だいぶ減ったので、以前の状態に復帰しよう)"
gamer.restore_memento(memento)
end
begin
sleep 1
rescue => e
# pass
end
puts ""
end
end
main
#!/usr/bin/ruby -Ku
class BigChar
def initialize(charname)
@charname = charname
begin
@fontdata = IO.read("big#{charname}.txt")
rescue => e
@fontdata = "#{charname}?"
end
end
def print
puts @fontdata
end
end
class BigCharFactory
@@singleton = new
@@pool = {}
def self.get_instance
return @@singleton
end
def get_big_char(charname)
bc = @@pool[charname]
if bc == nil
bc = BigChar.new(charname)
@@pool[charname] = bc
end
return bc
end
private_class_method :new
end
class BigString
def initialize(string)
@bigchars = Array.new(string.length)
factory = BigCharFactory.get_instance
@bigchars.length.times do |i|
@bigchars[i] = factory.get_big_char(string[i,1])
end
end
def print
@bigchars.length.times do |i|
@bigchars[i].print
end
end
end
def main(args)
if args.length == 0
puts "Usage: ruby #$0 digits"
puts "Example: ruby #$0 1212123"
exit(0)
end
bs = BigString.new(args[0])
bs.print
end
main(ARGV)
#!/usr/bin/ruby -Ku
class Printer
def initialize(name = "")
if name == ""
heavy_job("Printerのインスタンスを生成中")
else
@name = name
heavy_job("Printerのインスタンス(#{name})を生成中")
end
end
def set_printer_name(name)
@name = name
end
def get_printer_name
return @name
end
def p(string)
puts "=== #@name ==="
puts string
end
def heavy_job(msg)
STDOUT.sync = true
print msg
5.times do
begin
sleep(1)
rescue => e
# pass
end
print "."
end
puts "完了。"
end
end
class Printable
def set_print_name(name)
# pass
end
def get_print_name
# pass
end
def p(string)
# pass
end
end
class PrinterProxy
def initialize(name = "")
@name = name
end
def set_printer_name(name)
if @real != nil
@real.set_printer_name(name)
end
@name = name
end
def get_printer_name
return @name
end
def p(string)
realize
@real.p(string)
end
def realize
if @real == nil
@real = Printer.new(@name)
end
end
end
def main
pr = PrinterProxy.new("Alice")
puts "名前は現在#{pr.get_printer_name}です。"
pr.set_printer_name("Bob")
puts "名前は現在#{pr.get_printer_name}です。"
pr.p("Hello, world.")
end
main

デザインパターン手習

『増補改訂版 Java言語で学ぶデザインパターン入門』(結城 浩, 2004)にあるデザインパターンを 学んだ頃 Ruby に慣れたいと思ってたので、 Ruby で各デザインパターンを実装した.

※2012年8月頃に書いたコードをまとめたもの. 今見返すと当時はあまり理解してなかった内容も多く, ぜひもう一度手を動かしながら読み返したい本.

................
................
................
................
..##########....
................
................
................
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
........##......
......####......
....##..##......
..##....##......
..##########....
........##......
......######....
................
..##########....
..##............
..##............
..########......
..........##....
..##......##....
....######......
................
....######......
..##......##....
..##............
..########......
..##......##....
..##......##....
....######......
................
..##########....
..##......##....
..........##....
........##......
......##........
......##........
......##........
................
....######......
..##......##....
..##......##....
....######......
..##......##....
..##......##....
....######......
................
....######......
..##......##....
..##......##....
....########....
..........##....
..##......##....
....######......
................
hyuki@hyuki.com=Hiroshi Yuki
hanako@hyuki.com=Hanako Sato
tomura@hyuki.com=Tomura
mamoru@hyuki.com=Mamoru Takahashi
#!/usr/bin/ruby -Ku
# 文字列の表示幅(半角何個分)を返す.
# 暗に全角文字 = 3バイト と仮定している.
# 厳密には http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt
# を参照した実装を行う必要がある
class String
def width
b = self.size # n * 1 + w * 3
l = self.split(//u).length # n * 1 + w * 1
return (b + l) / 2 # n * 1 + w * 2
end
end
if __FILE__ == $0
def demo(string)
width = string.width
puts %{string #=> "#{string}"}
puts "string.width #=> #{width}"
puts "|#{string}|"
puts "|#{'-' * width}| #{width}"
puts ""
end
demo("Hello, world.")
demo("増補改訂版 Java言語で学ぶデザインパターン入門 (結城 浩)")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment