当前位置: 首页 > news >正文

Ruby模块和程序组织

和类一样,模块是一组方法和常量的集合。
和类不同,模块没有实例,取而代之的是可以将特殊模块的功能添加到一个类或者指定对象之中。
Class类是Module类的一个子类,因此每一个类对象也是一个模块对象

一、模块创建和基础应用

编写一个模块和编写类差不多,只是用module关键字在定义开始的位置取代class关键字而已。
Ruby模块是一种代码重用的方式,可以用来定义可重用的代码片段。模块中的方法可以被其他Ruby类或模块使用,就像它们是类的一部分一样。模块的名字就是模块的标识符,它不需要与文件名相同。
下面是一个创建和使用Ruby模块的基本示例:

# 创建一个模块  
module MyModule  def my_method  "Hello, World!"  end  
end  # 在另一个类中使用这个模块  
class MyClass  include MyModule  def call_my_method  my_method  end  
end  # 创建一个对象并调用方法  
obj = MyClass.new  
puts obj.call_my_method # 输出 "Hello, World!"

在这个例子中,我们首先定义了一个名为MyModule的模块,其中包含一个名为my_method的方法。然后,我们在MyClass中通过include MyModule语句将这个模块包含进来。这样,我们就可以在MyClass中使用MyModule中的方法了。最后,我们创建了一个MyClass的对象,并调用了call_my_method方法,该方法内部调用了我们定义的my_method方法。

Ruby模块对于代码的组织和重用非常有用。它们可以包含一组相关的函数,这些函数可以在多个不同的类或对象中使用。通过使用模块,我们可以避免在多个地方重复编写相同的代码,并且可以使代码更加清晰、易于理解和维护。

1、使用模块封装一个栈

模块提供了一种收集和封装行为的方式。一个典型的模块包含一些方法,这些方法最终将会与拥有对象全部功能的一个特定子集关联。
栈是一种后进先出的数据结构,当设计一个程序,以及定义一种行为或行为的集合时,这些行为可能会被多个类型的实体或对象表现出来,这时模块就是一种好的备选方案。

module Stacklikedef stack@stack ||= []enddef add_to_stack(obj)stack.push(obj)enddef take_from_stackstack.popend
end

2、将模块混合到类中

模块没有实例,不能直接new一个。

require_relative "stacklike"
class Stackinclude Stacklike
end

注意类名是一个名词,而模块名称是一个形容词

二、模块、类和方法查找

1、方法查找

清晰地理解对象发现方法的方式是件有趣的事。看下面这个例子:

module M def reportputs "'report' method in module M"end
endclass C include M 
endclass D < C 
endobj = D.new
obj.report

实例方法report被定义在模块M中。而模块M被混合到了类C中。类D是C的子类,obj是D的一个实例。通过这样的层级关系,对象obj便可以访问report方法。

2、同名方法的多次定义

在类中定义一个方法两次,第二个定义将会取代第一次。这在模块中依然如此。
对象的方法可以从任意数量的类和模块中获得。
一个对象在其查找路径中有两个同名方法的另一种情况是:当一个类混合了两个或多个模块时,将搜索到方法的多个实现。这样的例子中,按照包含的逆序查找模块,这意味着最新混合到类中的模块将最先被搜索到。假如最新混合得到类的模块包含一个同名的方法,其方法在早先被混合的模块中出现过,最新被混合的模块中的那个版本的方法将会占据优先级,因为新混合的模块在查找路径中有最短的距离。

module M def reportputs "'report' method in module M"end
endmodule N def reportputs "'report' method in module N"end 
endclass C include M include N 
endc = C.new
c.report

这将会输出'report' method in module N
但是在包含N之后再次包含M

class C include M include N include M
endc = C.new
c.report

这仍将会输出'report' method in module N。因为M已经存在于查找路径中,第二次包含M没有任何效果。N仍然被认为是最新引入的模块。

3、prepend

在Ruby中,prepend是一个方法,用于将一个模块或类添加到另一个类的继承链中。它使得被prepend的模块或类的方法在原类的方法之前被调用。

module MeFirstdef reportputs "Hello from module!"end
endclass Personprepend MeFirstdef reportputs "Hello from class!"end
endp = Person.new
p.report

运行这段代码将会输出

Hello from module!

4、方法查找的顺序

为了将消息解析为可用的方法,对象会在如下位置搜索方法
1、被前置在它所属类中的模块,按照与前置相反的顺序。
2、它的类中
3、被包含在它所属类中的模块,按照与包含相反的顺序
4、前置到它超类中的方法,按照与包含相反的顺序
5、它所属的超类
6、包含在它所属超类中的模块
7、同样地,达到Object和BasicObject

5、使用super向上追溯方法路径

在Ruby中,super关键字用于调用父类中的方法。当子类重写父类的方法时,使用super可以调用父类中被重写的方法。

class ParentClass  def method  "Parent method"  end  
end  class ChildClass < ParentClass  def method  super.method + " child method"  end  
end  child = ChildClass.new  
puts child.method # 输出 "Parent method child method"

三、method_missing方法

method_missing是Ruby语言中的一个特殊方法。当试图调用一个不存在的方法时,Ruby会自动调用method_missing方法。这个方法允许你实现自定义的行为来处理缺失的方法调用。

class MyClass  def method_missing(method_name, *args)  if method_name.to_s == "hello"  "Hello, World!"  else  super  end  end  
end  obj = MyClass.new  
obj.hello # 输出 "Hello, World!"  
obj.foo   # 抛出 NoMethodError 异常,因为方法 "foo" 不存在

在上面的示例中,当调用obj.hello时,由于MyClass类中没有定义名为hello的方法,Ruby会自动调用method_missing方法。在method_missing方法中,我们根据方法名进行判断,如果方法名是"hello",则返回"Hello, World!“,否则调用super方法来抛出异常。这样,当我们调用obj.hello时,会得到预期的输出结果"Hello, World!”。而当我们尝试调用一个不存在的方法如obj.foo时,会抛出NoMethodError异常。
使用method_missing方法可以实现在运行时动态处理缺失的方法调用,提供了很大的灵活性和扩展性。但需要注意的是,过度使用method_missing可能会导致代码难以理解和维护,因此在使用时需要权衡利弊。

http://www.lryc.cn/news/212781.html

相关文章:

  • 14、SpringCloud -- WebSocket 实时通知用户
  • 智能井盖传感器推荐,万宾科技助力城市信息化建设
  • 3D模型格式转换工具HOOPS Exchange对工业级3D产品HOOPS的支持与应用
  • table 表体滚动, 表头、表尾固定
  • 第57篇-某钩招聘网站加密参数分析【2023-10-31】
  • C语言数据结构之数据结构入门
  • 如何知道服务器的某个端口是否打开
  • 【ICCV‘23】One-shot Implicit Animatable Avatars with Model-based Priors
  • 关于息肉检测和识别项目的总结
  • Jetson Xavier NX FFmpeg支持硬件编解码
  • 518抽奖软件,为什么说比别的抽奖软件更美观精美?
  • React的组件学习
  • uni-app配置微信开发者工具
  • 肺癌不再是老年病:33岁作家的离世引发关注,有这些情况的请注意
  • 【兔子王赠书第4期】用ChatGPT轻松玩转机器学习与深度学习
  • Ubuntu18.04 ROS Melodic的cv_bridge指向问题(四种方式,包括opencv4)(转载)
  • Android任务栈和启动模式
  • 电脑加密软件哪个好?电脑加密软件推荐
  • 如何优雅地单元测试 Kotlin/Java 中的 private 方法?
  • 单元测试,集成测试,系统测试的区别是什么?
  • 数据结构(超详细讲解!!)第十八节 串(KMP算法)
  • 软考_软件设计师
  • 大数据之LibrA数据库系统告警处理(ALM-12004 OLdap资源异常)
  • 详解—数据结构《树和二叉树》
  • 菜单管理中icon图标回显
  • Postman如何导出接口的几种方法
  • Java进阶(Set)——面试时Set常见问题解读 结合源码分析
  • 【强化学习】12 —— 策略梯度(REINFORCE )
  • Kubernetes Taint(污点) 和 Toleration(容忍)
  • 使用cv::FileStorage时出错 Can‘t open file: yaml‘ in read mode