文档章节

Ruby中类 模块 单例方法 总结

穿山
 穿山
发布于 2017/11/16 11:44
字数 2597
阅读 63
收藏 0
# 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

 

© 著作权归作者所有

穿山
粉丝 9
博文 33
码字总数 18655
作品 0
南京
私信 提问
Ruby 模块(Mix-in)

是 Ruby的特色功能之一. 如果说类表现的是实物的实体(数据)及其行为(处理), 那么模块表现的就只是事物的行为部分. 模块与类有以下两点不同: 模块不能拥有实例 模块不能被继承 利用 Mix-in 扩...

changsanjiang
2017/10/23
0
0
Ruby中的继承、原型、面向对象、访问域

先有类还是先有对象 从鸡蛋悖论解决可以悟到一个道理,不要从常识上假设非此即彼和绝对静止。 Ruby中的类和对象正是这么个东西 我们创建一个类,那它就是Class这个对象的实例,而Class,于是...

可数局部基
02/24
8
0
理解 Ruby 2.0 中方法是如何查找与执行

预先介绍Ruby2.0是一个好的机会去回顾如何精确的用Ruby去树立方法调用。 理解查找方法对于掌握Ruby的层次类是很有必要的。我准备的这篇文章有很多的代码例子;你需要用Ruby 1.9.2 或者 更新的...

Wyatt
2013/03/24
1K
6
1.单例模式

设计模式并非是难以理解, 或是难以应用到实践中的, 相反的, 设计模式恰恰代表了某些场景下的最佳实践! 这些设计模式通常被有经验的开发者们所采用。 设计模式是开发者们在开发过程中面临的一...

mtshen
2018/01/04
0
0
设计模式(一) ---- 单例模式

概念:一套被反复使用的,多数人知晓的,经过分类,编目的代码设计经验的总结 优点: 都是优秀的使用案例 可提高代码的重用性 使得代码易于理解 保证代码的可靠性 单例模式 引入: 现实生活中有些场...

文心丶雕龙
2016/06/30
21
0

没有更多内容

加载失败,请刷新页面

加载更多

Java Web 中对 ServletRequest 的一些非常规操作解决方案

1. 前言 ServletRequest 是我们搞 Java Web 经常接触的 Servlet Api 。有些时候我们要经常对其进行一些操作。这里列举一些经常的难点操作。 2. 提取 body 中的数据 前后端交互我们会在 body...

码农小胖哥
24分钟前
2
0
《Dual Encoding U-Net for Retinal Vessel Segmentation》阅读笔记-MICCAI2019

作者:Bo Wang1,2, Shuang Qiu2, and Huiguang He1,2,3 目的:Retinal Vessel Segmentation is an essential step for the early diagnosis of eye-related diseases, such as diabetes and ......

JungleKing
27分钟前
2
0
一次看懂 Https 证书认证

TLS > 传输层安全性协定 TLS(Transport Layer Security),及其前身安全套接层 SSL(Secure Sockets Layer)是一种安全协议,目的是为网际网路通信,提供安全及数据完整性保障。 如图,TLS...

极客收藏夹
41分钟前
4
0
https证书买哪家好?有哪些供应商

在选购https证书前除了要了解类型外,还需要了解https证书供应商,毕竟不同的供应商,提供的产品质量与服务也是有差异的。今天小编就为大家讲讲https证书供应商方面的内容,希望各位会喜欢。...

安信证书
43分钟前
5
0
Zuul 配置

概述:zuul底层是基于servlet,是由一系列的filter链构成。 1、路由配置 a、单例serverId映射 zuul: routes: client-a: path: /client/** serviceId: client-a 意思是...

java框架开发者
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部