『増補改訂版 Java言語で学ぶデザインパターン入門』(結城 浩, 2004)にあるデザインパターンを 学んだ頃 Ruby に慣れたいと思ってたので、 Ruby で各デザインパターンを実装した.
※2012年8月頃に書いたコードをまとめたもの. 今見返すと当時はあまり理解してなかった内容も多く, ぜひもう一度手を動かしながら読み返したい本.
#!/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 | |
close | |
end | |
end | |
class CountDisplay < Display | |
def initialize(impl) | |
super | |
end | |
def multi_display(times) | |
open | |
times.times do | |
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("[email protected]", "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 |
................ | |
................ | |
................ | |
................ | |
..##########.... | |
................ | |
................ | |
................ |
....######...... | |
..##......##.... | |
..##......##.... | |
..##......##.... | |
..##......##.... | |
..##......##.... | |
....######...... | |
................ |
......##........ | |
..######........ | |
......##........ | |
......##........ | |
......##........ | |
......##........ | |
..##########.... | |
................ |
....######...... | |
..##......##.... | |
..........##.... | |
......####...... | |
....##.......... | |
..##............ | |
..##########.... | |
................ |
....######...... | |
..##......##.... | |
..........##.... | |
......####...... | |
..........##.... | |
..##......##.... | |
....######...... | |
................ |
........##...... | |
......####...... | |
....##..##...... | |
..##....##...... | |
..##########.... | |
........##...... | |
......######.... | |
................ |
..##########.... | |
..##............ | |
..##............ | |
..########...... | |
..........##.... | |
..##......##.... | |
....######...... | |
................ |
....######...... | |
..##......##.... | |
..##............ | |
..########...... | |
..##......##.... | |
..##......##.... | |
....######...... | |
................ |
..##########.... | |
..##......##.... | |
..........##.... | |
........##...... | |
......##........ | |
......##........ | |
......##........ | |
................ |
....######...... | |
..##......##.... | |
..##......##.... | |
....######...... | |
..##......##.... | |
..##......##.... | |
....######...... | |
................ |
....######...... | |
..##......##.... | |
..##......##.... | |
....########.... | |
..........##.... | |
..##......##.... | |
....######...... | |
................ |
[email protected]=Hiroshi Yuki | |
[email protected]=Hanako Sato | |
[email protected]=Tomura | |
[email protected]=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 |