Ruby学习笔记(16)_面对对象

2017-10-23 18:59:22来源:CSDN作者:slowsnowscar人点击

分享

Ruby 是纯面向对象的语言,Ruby 中的一切都是以对象的形式出现。Ruby 中的每个值都是一个对象,即使是最原始的东西:字符串、数字,甚至连 true 和 false 都是对象。类本身也是一个对象,是 Class 类的一个实例。本章将向您讲解所有与 Ruby 面向对象相关的主要功能。

类用于指定对象的形式,它结合了数据表示法和方法,把数据整理成一个整齐的包。类中的数据和方法被称为类的成员。

Ruby 类定义

类定义以关键字 class 开始,后跟类名称,最后以一个 end 进行分隔表示终止该类定义。例如,我们使用关键字 class 来定义 Box 类,如下所示:

class Box    codeend

按照惯例,名称必须以大写字母开头,如果包含多个单词,每个单词首字母大写,但此间没有分隔符(例如:CamelCase)。

initialize 方法

initialize 方法是一个标准的 Ruby 类方法,是类的构造函数,与其他面向对象编程语言中的 constructor 工作原理类似。当您想要在创建对象的同时初始化一些类变量,initialize 方法就派上用场了。该方法带有一系列参数,与其他 Ruby 方法一样,使用该方法时,必须在前面放置 def 关键字,如下所示:

class Box   def initialize(w,h)      @width, @height = w, h   endend

实例变量

实例变量是类属性,它们在使用类创建对象时就变成对象的属性。每个对象的属性是单独赋值的,和其他对象之间不共享值。在类的内部,是使用 @ 运算符访问这些属性,在类的外部,则是使用称为访问器方法的公共方法进行访问。下面我们以上面定义的类 Box 为实例,把 @width 和 @height 作为类 Box 的实例变量。

class Box   def initialize(w,h)      # 给实例变量赋值      @width, @height = w, h   endend

类的继承

继承,是面向对象编程中最重要的概念之一。继承允许我们根据另一个类定义一个类,这样使得创建和维护应用程序变得更加容易。
继承有助于重用代码和快速执行.
不幸的是,Ruby 不支持多继承,但是 Ruby 支持 mixins。mixin 就像是多继承的一个特定实现,在多继承中,只有接口部分是可继承的。
当创建类时,程序员可以直接指定新类继承自某个已有类的成员,这样就不用从头编写新的数据成员和成员函数。这个已有类被称为基类或父类,新类被称为派生类或子类。
Ruby 也提供了子类化的概念,子类化即继承,下面的实例解释了这个概念。扩展一个类的语法非常简单。只要添加一个 < 字符和父类的名称到类语句中即可。例如,下面定义了类 BigBox 是 Box 的子类:

#! /usr/bin/ruby -wclass Box    def initialize(w,h)        @width,@height = w,h    end    def getArea        @width * @height    endend#定义子类class Bigbox < Box    def printArea        @area = getArea        puts "big box area is : #@area"    endendbox = Bigbox.new(10,20)box.printArea

结果:
big box area is : 200

方法重载

虽然您可以在派生类中添加新的功能,但有时您可能想要改变已经在父类中定义的方法的行为。这时您可以保持方法名称不变,重载方法的功能即可,如下面实例所示:

#!/usr/bin/ruby -w# 定义类class Box   # 构造器方法   def initialize(w,h)      @width, @height = w, h   end   # 实例方法   def getArea      @width * @height   endend# 定义子类class BigBox < Box   # 改变已有的 getArea 方法   def getArea      @area = @width + @height      puts "Big box area is : #@area"   endend# 创建对象box = BigBox.new(10, 20)# 使用重载的方法输出面积box.getArea()

冻结对象

有时候,我们想要防止对象被改变。在 Object 中,freeze 方法可实现这点,它能有效地把一个对象变成一个常量。任何对象都可以通过调用 Object.freeze 进行冻结。冻结对象不能被修改,也就是说,您不能改变它的实例变量。
您可以使用 Object.frozen? 方法检查一个给定的对象是否已经被冻结。如果对象已被冻结,该方法将返回 true,否则返回一个 false 值。下面的实例解释了这个概念:

#!/usr/bin/ruby -w# 定义类class Box   # 构造器方法   def initialize(w,h)      @width, @height = w, h   end   # 访问器方法   def getWidth      @width   end   def getHeight      @height   end   # 设置器方法   def setWidth=(value)      @width = value   end   def setHeight=(value)      @height = value   endend# 创建对象box = Box.new(10, 20)# 让我们冻结该对象box.freezeif( box.frozen? )   puts "Box object is frozen object"else   puts "Box object is normal object"end# 现在尝试使用设置器方法box.setWidth = 30box.setHeight = 50# 使用访问器方法x = box.getWidth()y = box.getHeight()puts "Width of the box is : #{x}"puts "Height of the box is : #{y}"

结果:
Box object is frozen object
test.rb:20:in `setWidth=’: can’t modify frozen object (TypeError)
from test.rb:39

使用 allocate 创建对象

可能有一种情况,您想要在不调用对象构造器 initialize 的情况下创建对象,即,使用 new 方法创建对象,在这种情况下,您可以调用 allocate 来创建一个未初始化的对象,如下面实例所示:

#!/usr/bin/ruby -w# 定义类class Box   attr_accessor :width, :height   # 构造器方法   def initialize(w,h)      @width, @height = w, h   end   # 实例方法   def getArea      @width * @height   endend# 使用 new 创建对象box1 = Box.new(10, 20)# 使用 allocate 创建两一个对象box2 = Box.allocate# 使用 box1 调用实例方法a = box1.getArea()puts "Area of the box is : #{a}"# 使用 box2 调用实例方法a = box2.getArea()puts "Area of the box is : #{a}"

结果:
Area of the box is : 200
test.rb:14: warning: instance variable @width not initialized
test.rb:14: warning: instance variable @height not initialized
test.rb:14:in getArea': undefined method*’
for nil:NilClass (NoMethodError) from test.rb:29

所以allocate应该比较适用于无参构造情况

#!/usr/bin/rubyclass Box   def hello      print "hello world"   endendbox1 = Box.allocatebox1.hello

结果:
hello world

类信息

Ruby的 self 和 Java 的 this 有相似之处,但又大不相同。Java的方法都是在实例方法中引用,所以this一般都是指向当前对象的。而Ruby的代码逐行执行,所以在不同的上下文(context)self就有了不同的含义。让我们来看看下面的实例:

#!/usr/bin/ruby -wclass Box   # 输出类信息   puts "Class of self = #{self.class}"   puts "Name of self = #{self.name}"endclass BigBox < Box     puts "Class of self = #{self.class}"   puts "Name of self = #{self.name}"end

结果:
Class of self = Class
Name of self = Box
Class of self = Class
Name of self = BigBox

这意味着类定义可通过把该类作为当前对象来执行,同时也意味着元类和父类中的该方法在方法定义执行期间是可用的。


访问器(getter) & 设置器(setter)方法

为了在类的外部读取类中已定义的变量,我们可以通过定义访问器(getter)方法来访问。下面的实例演示了访问器方法的用法:

实例:

#!/usr/bin/ruby -w# 定义类class Box   # 构造器方法   def initialize(w,h)      @width, @height = w, h   end   # 访问器方法   def getWidth      @width   end   def getHeight      @height   end   # 设置器方法   def setWidth=(value)      @width = value   end   def setHeight=(value)      @height = value   endend# 创建对象box = Box.new(10, 20)# 使用设置器方法box.setWidth = 30box.setHeight = 50# 使用访问器方法x = box.getWidth()y = box.getHeight()puts "盒子宽度 : #{x}"puts "盒子高度 : #{y}"

结果:
width is 30
height is 50

由于两种方法非常常用,Ruby 定义了 attr_accessor :variable_name、attr_reader :variable_name、attr_writer :variable_name 三种属性声明方法。其中:accessor=reader+writer。
同时注意:变量名前一定要带 : ,变量名之间要用 , 分割。
attr_accessor, attr_writer, attr_reader 有一些注意点, 在下一篇文章内容

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台