特異なんとか

特異クラス、メソッドについて存在は知っていたが、どんなときに使えばよいのかあまりピンとこなかった。で、今、タイムリーに思いついたネタを試してみたのでログ。

例えば、日付(date)とか時刻(time)をString型で持つ場合に、年、月だけとか、年月だけとか、分だけとかほしいことは良くあると思う。で、単純に実装すると、to_year見たいなヘルパーメソッドを用意することが多いだろう。

しかし、Rubyでは特異なんとかを使い、次のようにすることでなんともオブジェクト指向プログラミングらしい実装が可能だと気づいた。

  • 特異メソッドを使った場合
irb(main):001:0> class Foo
irb(main):002:1>   attr_accessor :time
irb(main):003:1>   def time=(value)
irb(main):004:2>     @time = value
irb(main):005:2>     def @time.hour
irb(main):006:3>       self.split(":").first
irb(main):007:3>     end
irb(main):008:2>   end
irb(main):009:1> end
=> nil
irb(main):010:0> foo = Foo.new
=> #
irb(main):011:0> foo.time = "12:34"
=> "12:34"
irb(main):012:0> foo.time.hour
=> "12"
  • 特異クラスを使った場合
irb(main):001:0> class Foo
irb(main):002:1>   attr_accessor :time
irb(main):003:1>   def time=(value)
irb(main):004:2>     @time = value
irb(main):005:2>     class << @time
irb(main):006:3>       def hour
irb(main):007:4>         self.split(":").first
irb(main):008:4>       end
irb(main):009:3>     end
irb(main):010:2>   end
irb(main):011:1> end
=> nil
irb(main):012:0> foo = Foo.new
=> #
irb(main):013:0> foo.time = "12:34"
=> "12:34"
irb(main):014:0> foo.time.hour
=> "12"

コスト云々は置いといたとして、とてもすっきり。なるほど、これはなかなかいいんじゃないか。ただ、特異クラスと特異メソッドの使い分けについては、まだハッキリしないのでもうちょっと勉強がひつようだ。