# 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