Ruby中類 模塊 單例方法 總結

# 1 單例方法的一種寫法和定義
# 在Ruby裏,能夠給具體的實例對象添加實例方法,這個方法只屬於這個實例
# 對象,咱們把這樣的方法稱之爲單例方法。
# 單例方法也叫做單件方法。定義單例方法,首先要生成一個實例對象,其次,
# 要在方法名前加上對象名和一個點號「.」。
# 在下面示例中,對象p1不能夠laugh , laugh方法只屬於p2對象。
# 實例方法,屬於類的每一個實例對象。單例方法只出如今單個實例對象中。用單
# 例方法能夠極大地豐富多態性在Ruby中的表現力。
class Person
end

p1 = Person.new
p2 = Person.new

def p1.lagugh
  puts '這是p1所獨有的單例子方法'
end

# 2 接下來咱們再看下導入模塊
module MyModule
  def a_method
    puts 'Hello MyModule'
  end
end

# 3 直接extend導入 將模塊的實例方法變爲類方法
class F
  extend MyModule
end
F.a_method

# 4 直接include導入 將模塊的實例方法變爲實例方法
class H
  include MyModule
end
h = H.new
h.a_method

# 5 class << self 中 include Mymodule
# 此寫法與類方法相同 使用include導入後變成類方法
class G
  class << self
    include MyModule
  end
end
G.a_method

# 6 用class << self 的寫法沒法使用extend
# class H
#   class << self
#     extend MyModule
#   end
# end
# H.a_method
# h.a_method
# H.a_method

# 7 使用實例 extend導入
obj = Object.new
obj.extend(MyModule)
obj.a_method

# 8 先說結論,本質上混入 module 都是將 Module 中的方法引入到對象(obj, 類E, 類F)的singleton_class(單件類)中.
# Ruby容許給單個對象增長方法,這種只針對單個對象生效的方法,稱爲單件方法。
# 9 extend與inclue 的區別
# include include to Object class
# extend include to Obj's singleton class
# 10總結 在類定義中使用include和extend時候
# include將類中的實例方法mixin變成類的實例方法
# extend將類中的實例方法變成類方法
# 但include可使用定義類方法的class << self方法導入
# extend則能夠經過實例mixn 究其緣由
# include是將模塊中的方法mixin對象的類中
# extend將模塊中的方法mixin對象的單例類中
# 11 單例方法只屬於這個對象 不屬於這個類 這個類的其餘實例都沒有這個方法 由於單例方法就是這個類的 單例類的實例方法
# 每一個對象的singleton class都不同 每一個對象都有本身的singleton class

str = 'Hello Ruby'
str2 = 'Hello Java'
def str.foo
  puts 'str的單例方法'
end

str.foo
# str2是沒有foo這個屬於str的單例方法的
# str2.foo

# 12 經過輸出可知 str 和 str2 這兩個類的內存地址不一樣 是相同類型的不相等的類
# str 和 str2 的類型也是 Class 類 把 Class當作對象
p str2.singleton_class
p str.singleton_class

# singleton_class 也是 Class類的一個對象
p str.singleton_class.class

# str2的實例方法中就沒有str實例方法foo
# 13 因此 方法foo 能夠當作是這個單例類的實例對象的方法
p str.singleton_class.instance_methods(false)
p str2.singleton_class.instance_methods(false)
p str.methods.grep(/foo/)
p str2.methods.grep(/foo/)

# 14 Ruby中類也是對象,而類名只是常量,因此在類上調用方法其實跟在對象上調用方法同樣:
# 15 類方法的實質是:它是一個類的單件方法,實際上若是比較單件方法的定義和類方法的定義,會發現其實兩者是同樣的.

## 在定義單件方法時,存在着類似的地方
## 兩者均使用了def關鍵詞作定義。
## 上面的object能夠是*對象的引用、常量類名或者self。
# 16 類方法定義與單例方法定義的比較
obj = Object.new

# 17 單例方法的定義
def obj.a_singleton_method
end

# 18 類方法的定義
class Myclass
  def self.clazz_method1
    puts '類方法1'
  end

  def Myclass.clazz_method2
    puts '類方法2'
  end

  class << self
    def clazz_method3
      puts '類方法3'
    end
  end
end

class << Myclass
  def clazz_method4
    puts '類方法4'
  end
end

def Myclass.clazz_method5
  puts '類方法5'
end

Myclass.clazz_method1
Myclass.clazz_method2
Myclass.clazz_method3
Myclass.clazz_method4
Myclass.clazz_method5

# 17 因此,單件方法能夠認爲是添加在對象的某個空間內只針對該對象有效的方法.
# 若是對象是個實例對象,添加的方法就是他的單件方法,
# 若是對象是個類,添加的方法就是這個類的類方法.

# 18 咱們知道Ruby中對象的方法的查找順序是:先向右,再向上,其含義就是先向右找到對象的類,
# 先在類的實例方法中嘗試查找,若是沒有找到,再繼續順着祖先鏈找.
# 前面介紹的單件方法是指那些只針對某個對象有效的方法,那麼若是爲一個對象定義了單件方法,
# 那麼這個單件方法的查找順序又應該是怎樣的?

class Myclass
  def my_method
  end
end

obj = Myclass.new

def obj.my_singleton_method
end

# 19 首先,單件方法不會在obj中,由於obj不是一個類,其次它也不在MyClass中,
# 那樣的話全部的MyClass實例都應該能共享調用這個方法,也就構不成單件類了.
# 同理,單件方法也不能在祖先鏈的某個位置(相似superclass: Object)中.
# 正確的位置是在單件類中,這個類其實就是咱們在irb中向對象詢問它的類時(obj.class)獲得的那個類,
# 不一樣的是這類與普通的類仍是有稍稍不一樣的.也能夠稱其爲元類或本徵類.
# 前說起到的實例對象的單件方法和類的類方法在建立上是相似的,
# 因此,經過的關鍵詞class配合特殊的語法應該能夠將其取到.class << obj.

# 20 若是存在單件方法那麼查找順序先去類去中的單例方法
class C
  def a_method
    puts 'C#a_method'
  end
end

class D < C
end

d = D.new
d.a_method # C#a_method

puts 'abc'.singleton_class #<Class:#<String:0x0000000002ec90a8>> String類的實例

class << d
  def d_method
    puts 'D#d_method'
  end
end

puts d.singleton_class #<Class:#<D:0x0000000002ec9238>> Class類的實例
puts d.singleton_class.class # singleton_class 的類型是Class
## 既然d.singleton_class 也是個類,那麼久試着查一下他的父類
puts d.singleton_class.superclass # D
## singleton_class是一個類,那麼它確定有父類,它的父類就是對象所屬的類
## 單例方法則存在於對象的特徵類中
# 單例方法存在於 對象單例類的實例方法中
puts d.singleton_class.instance_methods.grep(/d_method/)  ## d_method
puts d.singleton_class.instance_methods(false)

# 打開單件類
# Ruby 中 class 做用是把代碼的上下文變換到這個類中,也就是『打開類』,
# 同一個類能夠在任何地方被打開,也所以別人的類能夠被本身隨意打開並改寫.
# Ruby提供了兩種方法獲取單件類的引用,一種是經過傳統的關鍵詞class配合特殊的語法。
# 經過關鍵字 class << obj 打開實例對象的單件類空間,爲對象添加一系列的單件方法.
# 單件類的本質仍是一個類,是一個擁有惟一實例的類,因此叫單件類,或者單例類.

# 定義對象的一系列單件方法
# class << an_object
#   def a_singleton_method
#     puts '單例方法1'
#   end
# end

obj = Object.new
singleton_class = class << obj
                    self
end
p singleton_class.class

# 另外一個方法是,經過Object#singleton_class方法來得到單件類的引用:

p singleton_class = 'abc'.singleton_class  #<Class:#<String:0x0000000002ed7d10>>
p singleton_class.class # => Class

# 單件類的特性
# 1. 每一個單件類只有一個實例(被稱爲單件類的緣由),並且不能被繼承.
# 2. 單件類是一個對象的單件方法的存活所在.
# 3. 引入單件類後的方法查找
# 基於上面對單件類的基本認識,引入單件類後,Ruby的方法查找方式就不該該是先從其類(普通類)開始,
# 而是應該先從對象的單件類中開始查找,若是在單件類中沒有找到想要的方法,它纔會開始沿着類(普通類)開始,
# 再到祖先鏈上去找.這樣從單件類以後開始,一切又回到了咱們在沒有引入單件類時候的次序.
# 類方法,實例方法,單例方法
# 類方法只有類自己能夠調用,在ruby中,類方法是一種特殊的單例方法.
# 以前的例子中能夠獲得這樣的結論,singleton_class也是一種類,
# 在ruby中全部的類又都是對象.對象都有對應的singleton_class.

# Ruby 中方法的查找 遵循的規則是 'one step to the right, then up',即 向右一步而後向上.
# Ruby中查找順序
# 1singleton method defined on object
# 1* super class of singleton class
# 2 instance method defined in class
# 3 instance method defined in module
# reverse order in which they were included
# 4 instance method defined in ancestors
# 5 method_missing defined in Kernel module

class C
  def a_method
    puts 'C#a_method'
  end

  def self.a_class_method
    puts 'C#a_class_method'
  end
end

class D < C
end

obj = D.new

class << obj
  def a_singleton_method
    puts 'obj#a_singleton_method'
  end
end

# 欲調用 obj.a_singleton_method
# 此時調用對象是obj ,則會先去 #obj 處查找(向右一步)
# #obj
puts obj.a_singleton_method #obj#a_singleton_method

# 欲調用 D.a_class_method
# 此時調用對象是D ,則會先去 #D 出查找(向右一步)
# D.singleton_class 而後往上查(superclass)
# 單例類的父類就是對象所屬的類
puts D.singleton_class.superclass #<Class:C>
puts D.singleton_class.class #Class
puts D.singleton_class.class.superclass #Module
# #D -> #C
# D的類方法方法 a_class_method 在 #C 裏
puts D.a_class_method ## C#a_class_method

# 欲調用 obj.a_method
# 此時調用對象是obj ,則會先去 #obj 處查找(向右一步)
puts obj.singleton_class ## #<Class:#<D:0x007f9e88340b60>>
# obj.singleton_class 而後往上查(superclass)
puts obj.singleton_class.superclass ## D
# #obj 的父類 是 D 而後往上查(superclass)
puts D.superclass  ## C
# D 的父類 是 C
# 查找順序即: #obj -> D -> C
# D的實例方法 a_method 在 類C 裏
obj.a_method  ## C#a_method

###module
module C
  def foo
    puts 'foo in C'
  end
end

module D
  def foo
    puts 'foo in D'
  end
end

####classess
class A
  def foo
    puts 'foo in A'
  end
end

# class B < A
#   # include C
#   # include D
#   # def foo
#   #   puts 'foo in B'
#   # end
# end

class E
end

a = A.new
# b = B.new
e = E.new

# def b.foo
#   puts 'singleton foo'
# end

# 1 第一種狀況有單例方法
# 輸出 foo in A 和 singleton foo
a.foo
# b.foo
e.foo

# 2 第二種狀況去除 單例方法
# 輸出 foo in A  foo in B

# 3 第三種狀況去除 類中的實例方法
# 輸出foo in A 和 foo in D

# 4 第四種狀況 從父類中找實例方法
# 輸出foo in A 和 foo in A

# 5 父類中找不到的話就是方法丟失

# 總結找方法 先找單例中的方法 而後是類中定義的實例方法 模塊中的實例方法 祖先類的實例方法 underfined method
相關文章
相關標籤/搜索