ç¹ç°ã¡ã½ãã
ç¹å®ã®ã¤ã³ã¹ã¿ã³ã¹ã ããå®è¡ã§ããã¡ã½ãããç¹ç°ã¡ã½ãããã¨ããããã§ããç¹ç°ã¡ã½ãã以å¤ã«ã Ruby ã§ã¯"ç¹ç°"ã¨ããåèªãããã§ã¦ãããããªæ°ããã¾ããç¹ç°ã¡ã½ããã¯è±èªã§ã¯ "Singleton Method"ãã¨å¼ã°ããããã§ãã
a = "hello" b = a.dup def a.to_s "The value is '#{self}'" end
ãããã¯
class << a def to_s "The value is '#{self}'" end end
ã¨æ¸ããã¨ã®ãã¨ã夢ã®ä¸ã§è¦ãè¬ã®ææ³ "class << a" ã®è¬ã解ãã¾ããã
使ãã©ããã¯ã¾ã ããåãã£ã¦ãã¾ãããç¹å®ã®ã¤ã³ã¹ã¿ã³ã¹ã®åããã¡ãã£ã¨ã ãå¤ããããã¨ããæãªã©ã§ãããããa 㨠b ã¯åãã¤ã³ã¹ã¿ã³ã¹ã ããã©ããa ã®åãã ãã¡ãã£ã¨å¤ããããã§ãåãã¤ã³ã¿ãã§ã¼ã¹ã§ãããã¯æ±ããããã¨ãã£ãã±ã¼ã¹ãªã©...ãã©ãããå ´åã«ãããçºçãããããåé¡ã§ãã
ã¡ãã£ã¨ä»æ¥ã¯ Ruby ãåå¼·ãã¦ããæéããã¾ãããã¾ãããæ®å¿µã§ãã
method_missing 㨠instance_eval ã使ã£ã Decorator
Kernel#method_missing ã使ã£ã¦ã¿ããã§ãã
method_missing ã¯ãä»»æã®ã¯ã©ã¹ã«å¯¾ãã¦ã¡ã½ãããå¼ã³åºãããã¨ãã対象ã®ã¡ã½ããããã®ã¯ã©ã¹ã®ã¯ã©ã¹é層ã®ã©ãã«ãå®è£ ããã¦ãªãã£ãå ´åã«å¼ã³åºãããã¡ã½ãããã ããã§ããPerl ã® AUTOLOAD ã«ä¼¼ã¦ãã¾ãã
ããã§ãmethod_missing ã使ã£ã Decorator ãã¿ã¼ã³ãå®è£ ãã¦ã¿ã¾ãããDog ãªãã¸ã§ã¯ãã渡ãã¨ãã®ç¬ãå¼·ããªã StrongDog ã§ãã
dog = Dog.new('ãã') sdog = StrongDog.new(dog) dog.bark sdog.bark
ã¨ãã風ã«ä½¿ãã¾ããããã¨ã
ãã: ãããã ãã+1: brrr... ãã+1: ãããã
ã¨ãã風ãªçµæãè¿ãã¾ããDecorator ã® StrongDog ã§ããã㨠+1 ããã¦(ãã³ã°ã½ã¼ã+1ãã®ãããªã¤ã¡ã¼ã¸ã§ã)ãå¨å¢ããããªãã¾ããã¯ã©ã¹ã®å®è£ ã¯ä»¥ä¸ã®ããã«ãã¦ã¿ã¾ããã
class Dog attr :name def initialize(name) @name = name end def bark puts "#@name: ãããã" end end class StrongDog def initialize(dog) @dog = dog @dog.name << "+1" end def method_missing(method_id) puts "#{@dog.name}: brrr..." @dog.instance_eval(method_id.id2name) end end
StrongDog#bark ã¯å®è£ ãã¦ããªãã®ã§ããããå¼ã³åºããã㨠method_missing ãå¼ã³åºãããåå¦çãæãã ã㨠@dog ã«ååã®ã¡ã½ããã«å¦çã転éãã¾ãã
instance_eval ã®ç解ãã¾ã ä¸å®å ¨ã§ããããªãã¨ãªã使ã£ã¦ã¿ãããã¾ãããã¾ããã
ã¯ã©ã¹ã¯ãªãã¸ã§ã¯ãã§ãããã¯ã©ã¹åã¯å®æ°ã§ãã
ã¦ãµã®æ¬ãèªãã§ããã¨ãããå ã® Object#const_get ã®ç解ãå©ãã¦ããã解説ãè¦ã¤ãã¾ãããP.292 ã® "ã¯ã©ã¹åã¯å®æ°ã§ãã" ã®ç®æã§ãã
ã¾ããRuby ã®ã¯ã©ã¹ã¯ Class ãªãã¸ã§ã¯ãã¨ãããªãã¸ã§ã¯ãã§ããããããã£ã¦ãã¯ã©ã¹ã¡ã½ãããå¼ã³åºãã®ã¯ Class ãªãã¸ã§ã¯ãã«ã¡ãã»ã¼ã¸ãéä¿¡ãã¦ããã¨ãããã¨ã«ãªãã¾ããRuby ã®ç¹å¾´ã§ããããã¹ã¦ããªãã¸ã§ã¯ããã¨èãã¦ããæ³åããã®ã¯ Java ã®ããªããã£ãåããªãã¸ã§ã¯ãã§ããã¨ãããããã§ãããã¯ã©ã¹ããªãã¸ã§ã¯ãã§ããã¨ããã®ã¯é¢ç½ãã§ãã
$ irb irb(main):001:0> Object.const_get(:String).class => Class
ãããã«ãã¯ã©ã¹ãåå¾ãã¦ãã®ã¯ã©ã¹ã調ã¹ã㨠Class ã¯ã©ã¹ã§ãã
ã¯ã©ã¹ããªãã¸ã§ã¯ãã§ããã¨ãããã¨ã¯ãã¯ã©ã¹ãä»ã®ãªãã¸ã§ã¯ãã¨åãããã«æ±ããã¨ãã§ãã
- ã¯ã©ã¹ãã³ãã¼ããã
- ã¯ã©ã¹ã«ã¡ã½ããã渡ããã
- ã¯ã©ã¹ãæ·ãã¨ãã¦ä½¿ç¨ããã
ã¨ãã£ããã¨ãã§ããã¨ã¦ãµã®æ¬ã«æ¸ãã¦ãã¾ãã
irb#1(main):001:0> def factory(klass, *args) irb#1(main):002:1> klass.new(*args) irb#1(main):003:1> end => nil irb#1(main):004:0> factory(String, "Hello") => "Hello" irb#1(main):005:0> factory(Dir, ".") => #<Dir:0x31e3c0>
ããã
Klass
"Class" ã§ã¯ãªã "Klass" ã¨æ¸ãã®ã¯ãªã? ã®çãã¯ãid:drawnboy ããã«ããã¨
ãã¼ã«ã«å¤æ°ãªã¯ã©ã¹ãªãã¸ã§ã¯ããæãã¨ãã« âclassâ ã¯äºç´èªãªã®ã§ âklassâ ã¨æ¸ãããã§ãã
ã¨ã®ãã¨ã§ãã(æ¨æ©ã夢ã®ä¸ã§ã¾ãå¥ã®äººãåããã¨ãè¨ã£ã¦ããæ°ããã¾ãã) id:drawnbody ããã«ããã°ãKlass 㯠Smalltalk ç±æ¥ãããããªããã¨ã®ãã¨ãé¢ç½ããã§ããã®ã§å°ã Google ã§èª¿ã¹ã¦ã¿ã¾ããããç±æ¥ã«ã¤ãã¦è§£èª¬ãã¦ãããã¼ã¸ã¯ç°¡åã«ã¯è¦ã¤ããã¾ããã§ãããæ®å¿µã§ãã
alias ã使ã£ã Adapter ãã¿ã¼ã³
ruby ã«ã¯ alias å¼ã§ã¡ã½ãããæ¼ç®åãã°ãã¼ãã«å¤æ°ãæ£è¦è¡¨ç¾å¾æ¹åç §ã®å¥åãä½ããã¨ãã§ããããã§ããAdapter ãã¿ã¼ã³ ã Ruby ã£ã½ãããããã« alias ã使ã£ã¦æ¸ãæ¿ãã¦ã¿ã¾ãã
#!/usr/local/bin/ruby class Banner def initialize(string) @string = string end def show_with_paren puts "(#@string)" end def show_with_aster puts "*#@string*" end end class PrintBanner < Banner alias print_weak show_with_paren alias print_strong show_with_aster end p = PrintBanner.new("Hello") p.print_weak p.print_strong
ããã§ãã¾ãããã¾ãããå ã®ã³ã¼ãã Banner#show_with_paren ã PrintBanner#print_weak ã«å§è²ãã¦ããã ãã ã£ãã®ã§ alias ã使ã£ã¦ã¿ããã¨ãããã®ã§ãã
ãããã PrintBanner ãç¨æããªãã¦ã
class Banner alias print_weak show_with_paren alias print_strong show_with_aster end
ã§ãè¯ãããããã¾ãããå¾ãããããã§ãã¯ã©ã¹ã®æåãå¤ããããã®ãåçè¨èªã®è¯ãã¨ããã§ãã
ã¨ããã§ãã® aliasãææ³çã«ã¯ãæ°ããåå å¤ãååãã®é ã§ããããªãã¨ãªãéã®æ¹ãç´æçãªæ°ããã¾ããããããã®é ã«ãªã£ã¦ããã®ã¯ UNIX ã® alias ã³ãã³ããæèãã¦ãããããªã®ã§ããããã
Object#const_get
ã¯ã©ã¹åããã¯ã©ã¹ãå¾ãæ¹æ³ã¯ããªãã¡ã¬ã³ã¹ããã¥ã¢ã«ã«ãã㨠eval ã使ãæ¹æ³ãObject#const_get ã使ãæ¹æ³ã®äºéããããããã§ãã
#!/usr/local/bin/ruby class Player attr_accessor :name, :age def initialize(name, age) @name = name @age = age end end player1 = Object.const_get('Player').new('rubyo', 19) puts player1.name puts player1.age player2 = eval('Player').new('rubco', 18) puts player2.name puts player2.age
ãã®æã¯ã©ã¹åã Net::HTTP ã®ããã«ãã¹ããã¦ããå ´åã®æ¹æ³ã«ã¤ãã¦ãããã¥ã¢ã«ã«è§£èª¬ãããã¾ããã
eval ã§æååã"ã³ã¼ãä¸ã®ã¯ã©ã¹å"ã¨ãã¦æ±ããã¨ã«ã¤ãã¦ã¯ç解ã§ãã¾ãããä¸æ¹ã® const_get 㯠ri ããã¨
------------------------------------------------------- Module#const_get mod.const_get(sym) => obj ------------------------------------------------------------------------ Returns the value of the named constant in _mod_. Math.const_get(:PI) #=> 3.14159265358979
ã¨ããã¾ãããnamed å®æ°ã®å¤ãåå¾ãããå¼æ°ã¯ã·ã³ãã«ããã® Math ã®ä¾ãè¦ãã¨ç¹å®ã®ã¢ã¸ã¥ã¼ã«å ã§å®ç¾©ããã¦ããå®æ°ãåå¾ã§ãããã¨ãã風ã«è¦ãã¾ãã Math ã¢ã¸ã¥ã¼ã«ã®ä¸ã«ã¯ PI ã¨ããå®æ°ãå®ç¾©ããã¦ãã¦ããã®å¤ã¯ 3.14159... ã§ãããããã Math ã¢ã¸ã¥ã¼ã«ã®å¤ããåå¾ããæ段ã¨ã㦠const_get ãç¨æããã¦ãããã¨ãããã¨ã§ãããã
- Math ã¢ã¸ã¥ã¼ã«ã®ä¸ã®
- PI å®æ°ãåå¾ãã
- ãã®å¤ã¯ 3.14159...
ã¢ã¸ã¥ã¼ã«ã®ã¯ã©ã¹ã«ç¸å½ãã Module ã¯ã©ã¹ã«ã¯ constans ã¨ããã¡ã½ããããããããã§å®æ°ä¸è¦§ãåå¾ã§ãã¾ãã
$ irb irb(main):001:0> Math.constants => ["E", "PI"]
ã¨ã確ãã« Math ã¢ã¸ã¥ã¼ã«ã«ã¯ PI å®æ°ããããã¨ãåããã¾ãã
ãã¨ãã
Object.const_get('Player') #=> Player
ã¯ã©ãç解ããã°è¯ããã¨ããã¨ãå ã® Math ã®ãã®ããã®ã¾ã¾å½ã¦ã¯ããã¨
- Object ã¯ã©ã¹ã®ä¸ã®
- Player å®æ°ãåå¾ãã
- ãã®å¤ã¯ Player ã¨ããã¯ã©ã¹å( 'Player' ã¨ããæååã§ã¯ãªããã³ã¼ãä¸ã§ã¯ã©ã¹åã¨è§£éããã Player ã¨ããå¤)
ã¨è¨ã風ã«ãªãã¾ããã¨ãããã¨ã¯ Object ã¯ã©ã¹ã« Player ã¨ããå®æ°ãå®ç¾©ããã¦ãããã¨ã«ãªãã®ã§ããããããã§ã
#!/usr/local/bin/ruby class Player end Object.constants.each {|const| puts const }
ã¨ããã³ã¼ããæ¸ã確ããã¦ã¿ã¾ããã
$ ruby const_get.rb | grep 'Player' Player
確ãã« Player ã¨ããå®æ°ãè¦ã¤ããã¾ãããä¸æ¹ãclass Player ãå®ç¾©ãã¦ããªã段é㧠const_get ãã¦ã¿ã¾ãã
$ irb irb(main):001:0> Object.const_get(:Player) NameError: uninitialized constant Player from (irb):1:in `const_get' from (irb):1 irb(main):002:0> Object.const_get(:String) => String
çµã¿è¾¼ã¿ã¯ã©ã¹ã® String ã§ã¯çµæãè¿ãã®ã«å¯¾ãã¦ãå®ç¾©ããã¦ããªãã¯ã©ã¹ã® Player ã«ã¯çµæãè¿ãã¾ããã§ããã
ã¤ã¾ããObject ã¯ã©ã¹ã¯ããã®ã¢ããªã±ã¼ã·ã§ã³ã®ä¸ã§æ±ããã¯ã©ã¹ã®ã¯ã©ã¹åãå®æ°ã¨ãã¦æã¤ãããªæ©æ§ã«ãªã£ã¦ãããã¨ç解ãã¾ããã
Abstract Factory ãã¿ã¼ã³
id:hyuki ããã®ãã¶ã¤ã³ãã¿ã¼ã³æ¬ãã Abstract Factory ãã¿ã¼ã³ã移æ¤ãã¦ã¿ã¾ãã
#!/usr/local/bin/ruby class Item def initialize(caption) @caption = caption end end class Link < Item def initialize(caption, url) super(caption) @url = url end end class Tray < Item def initialize(caption) super(caption) @tray = Array.new end def add(item) @tray.push(item) end end class Page def initialize(title, author) @title = title @author = author @content = Array.new end def add(item) @content.push(item) end def output self.make_html end end class Factory def Factory.get_factory(classname) eval(classname).new end end class ListFactory < Factory def create_link(caption, url) ListLink.new(caption, url) end def create_tray(caption) ListTray.new(caption) end def create_page(title, author) ListPage.new(title, author) end end class ListLink < Link def make_html return "<li><a href=?"#@url?">#@caption</a></li>?n" end end class ListTray < Tray def make_html result = String.new result += "<li>#@caption?n" result += "<ul>?n" @tray.each do |item| result += item.make_html end result += "</ul>?n" result += "</li>" result end end class ListPage < Page def make_html list = @content.map{ |item| item.make_html }.join('') return <<EOS <html> <head><title>#@title</title></head> <body> <h1>#@title</h1> <ul> #{list} </ul> <hr><address>#@author</address> </body> </html> EOS end end if ARGV.size != 1 puts "Usage: #$0 <classname>" exit end factory = Factory.get_factory(ARGV.shift) hatena = factory.create_link("ã¯ã¦ãª", "http://www.hatena.ne.jp/") google = factory.create_link("Google", "http://www.google.com/") yahoo = factory.create_link("Yahoo!", "http://www.yahoo.com/") yahoo_jp = factory.create_link("Yahoo! Japan", "http://www.yahoo.co.jp/") yahoo_tray = factory.create_tray("Yahoo!") yahoo_tray.add(yahoo) yahoo_tray.add(yahoo_jp) page = factory.create_page("LinkPage", "ãã³ã") page.add(hatena) page.add(google) page.add(yahoo_tray) puts page.output
ãã®ã³ã¼ãããå¼æ°ã« "ListFactory" ã¨ä¸ãã¦å®è¡ããã¨ã
$ ruby abstract_factory.rb ListFactory <html> <head><title>LinkPage</title></head> <body> <h1>LinkPage</h1> <ul> <li><a href="http://www.hatena.ne.jp/">ã¯ã¦ãª</a></li> <li><a href="http://www.google.com/">Google</a></li> <li>Yahoo! <ul> <li><a href="http://www.yahoo.com/">Yahoo!</a></li> <li><a href="http://www.yahoo.co.jp/">Yahoo! Japan</a></li> </ul> </li> </ul> <hr><address>ãã³ã</address> </body> </html>
ã¨ãªãã¾ããããã¼ãæ¸ç±ã®ä¾ã¯ Java ã®ä¾ã§ãæ½è±¡ã¯ã©ã¹ã§ãµãã¯ã©ã¹ã®å®è£ ã«ç¸ãããããªãã Factory ã§ãã£ããããããåãæ¿ããã¨ããã®ãã¨ã¦ãç¾ããã®ã§ãããç¸ãããããããªã Ruby ã§ã¯ãã¾ãã¡ãã¾ãããªãæãããã¾ããItem ã Tray ã¯ã³ã³ã¹ãã©ã¯ã¿ã®ã¿ã®å®è£ ã§ããã
ããããã°ãä¸ã¤å¦ã³ã¾ããã
class Factory def Factory.get_factory(classname) begin eval(classname).new rescue NameError puts "Unknown factory class: #{classname}." end end end
ã¯ã©ã¹åã®æååããã¤ã³ã¹ã¿ã³ã¹ãçæããæ¹æ³ã§ããeval ã§æååãè©ä¾¡ãã¦ããã¡ã½ãããèµ·åããã¨ãã¾ãããã¾ããã
ã«é«æ©ãããå®è£ ãããã®ãè¦ã¤ãã¾ããã"ç´ æ´ãªå®è£ " ã®ã¨ãããæ®éã«ç§»æ¤ãããã®ã§ãã
- eval ã§ã¯ãªã Object.const_get ãã¤ãã£ã¦ãããconst_get ã£ã¦ä½ã§ãããã
- ãã¡ã¤ã«ã factory.rb / listfactory.rb / tablefactory.rb ã«åå²ãã¦ãã
- raise NotImplementedError ãè¨è¿°ãã¦ãç®æããã
ã¨ããã¨ãã以å¤ã¯ã»ã¨ãã©ä¸ç·ã®å®è£ ã§ããããã®ä»ã«
- Constant ã¡ã½ãã
- ãã¼ãã«ã¿ãã°
- ã¯ã©ã¹ã¤ã³ã¹ã¿ã³ã¹å¤æ°ã«ãããã¼ãã«ã¿ãã°
- å½åã®è¦ç´ã«ãããã¡ã¯ããª
ã¨ãããã®ãããã¾ãããåèã«ãªãã¾ãããã¾ããçèªãã¾ãã