Ruby 简明教程
Ruby - Object Oriented
Ruby 是一种纯面向对象语言,在 Ruby 中一切都被视为对象。Ruby 中的每个值都是一个对象,即使是最原始的东西:字符串、数字甚至是 true 和 false。即使类本身也是 Object 类的一个实例的对象。本章将带你了解与面向对象 Ruby 相关的全部主要功能。
Ruby is a pure object-oriented language and everything appears to Ruby as an object. Every value in Ruby is an object, even the most primitive things: strings, numbers and even true and false. Even a class itself is an object that is an instance of the Class class. This chapter will take you through all the major functionalities related to Object Oriented Ruby.
类用于指定对象的格式,它将数据表示和用于操作数据的函数组合在一个整洁的包中。类中的数据和方法称为类的成员。
A class is used to specify the form of an object and it combines data representation and methods for manipulating that data into one neat package. The data and methods within a class are called members of the class.
Ruby Class Definition
当你定义一个类时,你就定义了一个数据类型的蓝图。这实际上并不定义任何数据,但它确实定义了类名意味着什么,即类的对象将由什么组成,以及可以在这样的对象上执行什么操作。
When you define a class, you define a blueprint for a data type. This doesn’t actually define any data, but it does define what the class name means, that is, what an object of the class will consist of and what operations can be performed on such an object.
类定义以关键字 class 开始,随后是 class name ,并用 end 分隔。例如,我们使用关键字 class 定义 Box 类,如下所示:
A class definition starts with the keyword class followed by the class name and is delimited with an end. For example, we defined the Box class using the keyword class as follows −
class Box
code
end
名称必须以大写字母开头,并且根据惯例,包含多个单词的名称会将每个单词的首字母大写并连接在一起,并且没有分隔符(驼峰式命名法)。
The name must begin with a capital letter and by convention names that contain more than one word are run together with each word capitalized and no separating characters (CamelCase).
Define Ruby Objects
一个类为对象提供蓝图,因此一个对象基本上是从一个类中创建的。我们使用 new 关键字声明类的对象。以下语句声明类的两个对象 −
A class provides the blueprints for objects, so basically an object is created from a class. We declare objects of a class using new keyword. Following statements declare two objects of class Box −
box1 = Box.new
box2 = Box.new
The initialize Method
initialize method 是一个标准 Ruby 类方法,并且作用方式几乎与 constructor 在其他面向对象编程语言中的作用方式相同。如果你想要在创建对象的时候对一些类变量进行初始化,initialize 方法是很有用的。此方法可以接受一个参数列表,并且像任何其他 ruby 方法一样,它会以 def 关键字为前导,如下所示 −
The initialize method is a standard Ruby class method and works almost same way as constructor works in other object oriented programming languages. The initialize method is useful when you want to initialize some class variables at the time of object creation. This method may take a list of parameters and like any other ruby method it would be preceded by def keyword as shown below −
class Box
def initialize(w,h)
@width, @height = w, h
end
end
The instance Variables
instance variables 是一种类属性,一旦使用类创建了对象,它们就会成为对象的属性。每个对象的属性都单独分配,并且不与其他对象共享值。它们在类中使用 @ 运算符进行访问,但是要在类外部访问它们,我们使用 public 方法,它们称为 accessor methods 。如果我们采用上面定义的类 Box ,那么 @width 和 @height 就是类 Box 的实例变量。
The instance variables are kind of class attributes and they become properties of objects once objects are created using the class. Every object’s attributes are assigned individually and share no value with other objects. They are accessed using the @ operator within the class but to access them outside of the class we use public methods, which are called accessor methods. If we take the above defined class Box then @width and @height are instance variables for the class Box.
class Box
def initialize(w,h)
# assign instance variables
@width, @height = w, h
end
end
The accessor & setter Methods
要让变量在类外部可用,它们必须在 accessor methods 内进行定义,这些访问器方法也称为 getter 方法。以下示例显示了访问器方法的用法 −
To make the variables available from outside the class, they must be defined within accessor methods, these accessor methods are also known as a getter methods. Following example shows the usage of accessor methods −
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def printWidth
@width
end
def printHeight
@height
end
end
# create an object
box = Box.new(10, 20)
# use accessor methods
x = box.printWidth()
y = box.printHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Width of the box is : 10
Height of the box is : 20
与用于访问变量值的访问器方法类似,Ruby 提供了一种使用 setter methods 从类外部设置这些变量值的方法,如下定义 −
Similar to accessor methods, which are used to access the value of the variables, Ruby provides a way to set the values of those variables from outside of the class using setter methods, which are defined as below −
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def getWidth
@width
end
def getHeight
@height
end
# setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# create an object
box = Box.new(10, 20)
# use setter methods
box.setWidth = 30
box.setHeight = 50
# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Width of the box is : 30
Height of the box is : 50
The instance Methods
instance methods 的定义方式与我们使用 def 关键字定义任何其他方法的方式相同,并且它们只能使用类实例来使用,如下所示。它们的功能并不仅限于访问实例变量,还可以根据你的要求执行更多操作。
The instance methods are also defined in the same way as we define any other method using def keyword and they can be used using a class instance only as shown below. Their functionality is not limited to access the instance variables, but also they can do a lot more as per your requirement.
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Area of the box is : 200
The class Methods and Variables
class variables 是一个变量,它在类的所有实例中共享。换句话说,该变量只有一个实例,它由对象实例访问。类变量使用两个 @ 字符(@@)作为前缀。必须在类定义中初始化类变量,如下所示。
The class variables is a variable, which is shared between all instances of a class. In other words, there is one instance of the variable and it is accessed by object instances. Class variables are prefixed with two @ characters (@@). A class variable must be initialized within the class definition as shown below.
类方法使用 def self.methodname() 定义,它以 end 定界符结尾,并且会使用类名作为 classname.methodname 调用,如下例所示 −
A class method is defined using def self.methodname(), which ends with end delimiter and would be called using the class name as classname.methodname as shown in the following example −
#!/usr/bin/ruby -w
class Box
# Initialize our class variables
@@count = 0
def initialize(w,h)
# assign instance avriables
@width, @height = w, h
@@count += 1
end
def self.printCount()
puts "Box count is : #@@count"
end
end
# create two object
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)
# call class method to print box count
Box.printCount()
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Box count is : 2
The to_s Method
你定义的任何类都应具有 to_s 实例方法以返回对象的字符串表示形式。以下是一个简单的示例,用于表示 Box 对象的宽度和高度 −
Any class you define should have a to_s instance method to return a string representation of the object. Following is a simple example to represent a Box object in terms of width and height −
#!/usr/bin/ruby -w
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# define to_s method
def to_s
"(w:#@width,h:#@height)" # string formatting of the object.
end
end
# create an object
box = Box.new(10, 20)
# to_s method will be called in reference of string automatically.
puts "String representation of box is : #{box}"
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
String representation of box is : (w:10,h:20)
Access Control
Ruby 在实例方法级别提供三级保护,它们可能是 public, private, or protected 。Ruby 对实例和类变量不适用任何访问控制。
Ruby gives you three levels of protection at instance methods level, which may be public, private, or protected. Ruby does not apply any access control over instance and class variables.
-
Public Methods − Public methods can be called by anyone. Methods are public by default except for initialize, which is always private.
-
Private Methods − Private methods cannot be accessed, or even viewed from outside the class. Only the class methods can access private members.
-
Protected Methods − A protected method can be invoked only by objects of the defining class and its subclasses. Access is kept within the family.
以下是一个简单的示例,展示了所有三个访问修饰符的语法 −
Following is a simple example to show the syntax of all the three access modifiers −
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method by default it is public
def getArea
getWidth() * getHeight
end
# define private accessor methods
def getWidth
@width
end
def getHeight
@height
end
# make them private
private :getWidth, :getHeight
# instance method to print area
def printArea
@area = getWidth() * getHeight
puts "Big box area is : #@area"
end
# make it protected
protected :printArea
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
# try to call protected or methods
box.printArea()
当执行以上代码时,它会产生以下结果。在此,第一个方法成功调用,但第二个方法出现了问题。
When the above code is executed, it produces the following result. Here, first method is called successfully but second method gave a problem.
Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)
Class Inheritance
面向对象编程中最重要的概念之一是继承。继承允许我们在另一个类的基础上定义一个类,这使创建和维护应用程序变得更加容易。
One of the most important concepts in object-oriented programming is that of inheritance. Inheritance allows us to define a class in terms of another class, which makes it easier to create and maintain an application.
继承还提供了重用代码功能和快速实现时间的机会,但不幸的是,Ruby 不支持多层次继承,但 Ruby 支持 mixins 。混合就像多重继承的一种专门实现,其中仅继承接口部分。
Inheritance also provides an opportunity to reuse the code functionality and fast implementation time but unfortunately Ruby does not support multiple levels of inheritances but Ruby supports mixins. A mixin is like a specialized implementation of multiple inheritance in which only the interface portion is inherited.
在创建一个类时,程序员可以指定新类应该继承现有类的成员,而不是编写全新的数据成员和成员函数。这个现有的类被称为 base class or superclass ,新类被称为 derived class or sub-class 。
When creating a class, instead of writing completely new data members and member functions, the programmer can designate that the new class should inherit the members of an existing class. This existing class is called the base class or superclass, and the new class is referred to as the derived class or sub-class.
Ruby 也支持子类化的概念,即继承,以下示例解释了这个概念。扩展类的语法很简单。只需添加 < 字符和超类的名称到你的类语句中即可。例如,以下定义一个类 BigBox 作为 Box 的子类 −
Ruby also supports the concept of subclassing, i.e., inheritance and following example explains the concept. The syntax for extending a class is simple. Just add a < character and the name of the superclass to your class statement. For example, following define a class BigBox as a subclass of Box −
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# define a subclass
class BigBox < Box
# add a new instance method
def printArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# create an object
box = BigBox.new(10, 20)
# print the area
box.printArea()
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Big box area is : 200
Methods Overriding
尽管可以在派生类中添加新功能,但有时您想要更改父类中已定义的方法的行为。您可以通过保持方法名称相同并覆盖方法的功能来做到这一点,如下例所示 -
Though you can add new functionality in a derived class, but sometimes you would like to change the behavior of already defined method in a parent class. You can do so simply by keeping the method name same and overriding the functionality of the method as shown below in the example −
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# define a subclass
class BigBox < Box
# change existing getArea method as follows
def getArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# create an object
box = BigBox.new(10, 20)
# print the area using overriden method.
box.getArea()
Operator Overloading
我们希望 + 运算符使用 + 执行两个 Box 对象的向量加法,* 运算符根据一个标量乘以一个 Box 的宽度和高度,一元 - 运算符对 Box 的宽度和高度求反。下面是定义了数学运算符的 Box 类的版本 -
We’d like the + operator to perform vector addition of two Box objects using +, the * operator to multiply a Box width and height by a scalar, and the unary - operator to do negate the width and height of the Box. Here is a version of the Box class with mathematical operators defined −
class Box
def initialize(w,h) # Initialize the width and height
@width,@height = w, h
end
def +(other) # Define + to do vector addition
Box.new(@width + other.width, @height + other.height)
end
def -@ # Define unary minus to negate width and height
Box.new(-@width, -@height)
end
def *(scalar) # To perform scalar multiplication
Box.new(@width*scalar, @height*scalar)
end
end
Freezing Objects
有时,我们希望阻止对对象的更改。Object 中的 freeze 方法允许我们做到这一点,有效地将对象变成一个常量。可以通过调用 Object.freeze 来冻结任何对象。冻结的对象可能不会被修改:您不能更改其实例变量。
Sometimes, we want to prevent an object from being changed. The freeze method in Object allows us to do this, effectively turning an object into a constant. Any object can be frozen by invoking Object.freeze. A frozen object may not be modified: you can’t change its instance variables.
您可以使用 Object.frozen? 方法检查给定对象是否已冻结,该方法在对象被冻结的情况下返回 true,否则返回 false 值。以下示例阐明了概念 -
You can check if a given object is already frozen or not using Object.frozen? method, which returns true in case the object is frozen otherwise a false value is return. Following example clears the concept −
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def getWidth
@width
end
def getHeight
@height
end
# setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# create an object
box = Box.new(10, 20)
# let us freez this object
box.freeze
if( box.frozen? )
puts "Box object is frozen object"
else
puts "Box object is normal object"
end
# now try using setter methods
box.setWidth = 30
box.setHeight = 50
# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
from test.rb:39
Class Constants
您可以通过将直接数字或字符串值分配给一个变量来定义类中的常量,而该变量不用 @ 或 @@ 定义。约定上,我们将常量名称保持为大写。
You can define a constant inside a class by assigning a direct numeric or string value to a variable, which is defined without using either @ or @@. By convention, we keep constant names in upper case.
一旦定义了常量,您就不能更改它,但是您可以直接在类中访问常量,就像访问变量一样,但是如果您想在类外访问常量,则必须像下面示例中所示使用 classname::constant 。
Once a constant is defined, you cannot change its value but you can access a constant directly inside a class much like a variable but if you want to access a constant outside of the class then you would have to use classname::constant as shown in the below example.
#!/usr/bin/ruby -w
# define a class
class Box
BOX_COMPANY = "TATA Inc"
BOXWEIGHT = 10
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Area of the box is : 200
TATA Inc
Box weight is: 10
类常量可被继承并且可以像实例方法一样被覆盖。
Class constants are inherited and can be overridden like instance methods.
Create Object Using Allocate
当您想在不调用其构造函数 initialize (即使用 new 方法)的情况下创建对象时,可能会出现这种情况,在这种情况下,您可以调用 allocate,它将为您创建一个未初始化的对象,如下例所示 -
There may be a situation when you want to create an object without calling its constructor initialize i.e. using new method, in such case you can call allocate, which will create an uninitialized object for you as in the following example −
#!/usr/bin/ruby -w
# define a class
class Box
attr_accessor :width, :height
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object using new
box1 = Box.new(10, 20)
# create another object using allocate
box2 = Box.allocate
# call instance method using box1
a = box1.getArea()
puts "Area of the box is : #{a}"
# call instance method using box2
a = box2.getArea()
puts "Area of the box is : #{a}"
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
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
Class Information
如果类定义是可执行代码,这意味着它们在某个对象的上下文中执行:self 必须引用某些东西。让我们找出是什么。
If class definitions are executable code, this implies that they execute in the context of some object: self must reference something. Let’s find out what it is.
#!/usr/bin/ruby -w
class Box
# print class information
puts "Type of self = #{self.type}"
puts "Name of self = #{self.name}"
end
执行上述代码后,将生成以下结果 −
When the above code is executed, it produces the following result −
Type of self = Class
Name of self = Box
这意味着类定义以该类为当前对象执行。这意味着在执行方法定义期间将可以使用元类及其超类中的方法。
This means that a class definition is executed with that class as the current object. This means that methods in the metaclass and its superclasses will be available during the execution of the method definition.