單例方法、實例方法、類別方法


在Ruby中,可以為單一物件定義方法。例如:
>> class Some; end
=> nil
>> s1 = Some.new
=> #<Some:0x25b2568>
>> def s1.some
>>     puts "some"
>> end
=> nil
>> s1.some
some
=> nil
>> s2 = Some.new
=> #<Some:0x278ee30>
>> s2.some
NoMethodError: undefined method `some' for #<Some:0x278ee30>
        from (irb):8
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>


上例中,定義於s1上的some方法,稱為s1參考物件的單例方法(Singleton method),僅屬於s1參考物件所擁有,同為Some實例的s2不會擁有該方法。如果想移除物件上的單例方法,可以如下:
>> class << s1
>>     remove_method :some
>> end
=> #<Class:#<Some:0x27c8700>>
>> s1.some
NoMethodError: undefined method `some' for #<Some:0x27c8700>
        from (irb):9
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>


實例方法是定義在類別上,而之後會再談到,單例方法實際上是定義在物件的匿名單例類別(Anonymous singleton class)上,class << object語法,就是用來開啟object的單例類別,由於<<在Ruby中往往有附加的意涵,而單例類別是沒有名稱的,所以class << object也可讀作,在object的匿名單例類別中追加定義。

如果想讓類別實例都擁有的方法,必須在類別中定義:
>> class Some
>>     def some
>>         puts "some"
>>     end
>> end
=> nil
>> s1 = Some.new
=> #<Some:0x5179c8>
>> s2 = Some.new
=> #<Some:0x2991048>
>> s1.some
some
=> nil
>> s2.some
some
=> nil
>>


上例中定義了Some實例方法(Instance method),所有Some實例都將擁有該方法。如果想移除實例方法,可以如下:
>> class Some
>>     remove_method :some
>> end
=> Some
>> s1.some
NoMethodError: undefined method `some' for #<Some:0x5179c8>
        from (irb):16
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>> s2.some
NoMethodError: undefined method `some' for #<Some:0x2991048>
        from (irb):17
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>


在Ruby中,所有東西都是物件,類別也是物件,具體來說,類別是Class實例,既然類別是物件,也就可以為Class的實例定義單例方法。例如:
>> class Some; end
=> nil
>> Some.class
=> Class
>> def Some.action
>>     puts "Some.action"
>> end
=> nil
>> Some.action
Some.action
=> nil
>>


上例也可以改為以下:
>> class Some
>>     def Some.action
>>         puts "Some.action"
>>     end
>> end
=> nil
>> Some.action
Some.action
=> nil
>>


通常會稱以上定義了Some的action類別方法(Class method),實際上,類別方法就是Class實例上的單例方法,也就是個別類別自己擁有的方法。

既然類別方法為Class實例的單例方法,那麼也就可以如下移除類別方法:
>> class Some
>>    def Some.some
>>         puts "some"
>>     end
>> end
=> nil
>> Some.some
some
=> nil
>> class << Some
>>     remove_method :some
>> end
=> #<Class:Some>
>> Some.some
NoMethodError: undefined method `some' for Some:Class
        from (irb):13
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>


類別方法預設為公開,如果想要將類別方法設為私有,可以使用private_class_method 方法,反之,則可以使用public_class_method。例如:
>> class Some
>>     def Some.some
>>         puts "some"
>>     end
>>     private_class_method :some
>> end
=> Some
>> Some.some

NoMethodError: private method `some' called for Some:Class
        from (irb):13
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>> class Some
>>     public_class_method :some
>> end
=> Some
>> Some.some
some
=> nil
>>


如果你在類別中定義常數,則外界可以透過類別::常數名稱來存 取。例如:
>> class Some
>>     X = 10
>> end
=> 10
>> Some::X
=> 10
>>


可以看到,在類別中定義常數,其實比較是將類別作為名稱空間,為管理變數的一種方式。