Ruby object-oriented


Ruby is a purely object-oriented language, and everything in Ruby appears in the form of objects. Every value in Ruby is an object, even the most primitive things: strings, numbers, even true and false are objects. The class itself is also an object, which is an instance of the Class class. This chapter will teach you about all the major features related to object-oriented Ruby.

Classes are used to specify the form of objects, which combine data representation and methods to organize data into a neat package. The data and methods in a class are called members of the class.

Ruby Class Definition

When you define a class, you are actually defining a blueprint of a data type. This does not actually define any data, but rather defines what the name of the class means, that is, what an object of the class will consist of, and what operations can be performed on the object.

The class definition starts with the keyword class, followed by class name, and finally separated by an end to terminate the class definition. For example, we use the keyword class to define the Box class as follows:

class Box
   code
end

By convention, the name must start with a capital letter. If it contains multiple words, the first letter of each word is capitalized, but there is no separation between them. character (for example: CamelCase).

Defining Ruby Objects

Classes provide the blueprint of objects, so basically, objects are created based on classes. We declare objects of a class using the new keyword. The following statement declares two objects of class Box:

box1 = Box.new
box2 = Box.new

initialize method

initialize method is a standard Ruby class method, which is the constructor of the class, and constructor in other object-oriented programming languages ​​works similarly. The initialize method comes in handy when you want to initialize some class variables while creating an object. This method takes a series of parameters. Like other Ruby methods, when using this method, you must place the def keyword in front, as follows:

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

Instance variable

Instance variables are class attributes. They become attributes of the object when using the class to create an object. The properties of each object are assigned individually and do not share values ​​with other objects. Inside the class, these properties are accessed using the @ operator, and outside the class, they are accessed using public methods called accessor methods. Below we take the class Box defined above as an instance, and use @width and @height as instance variables of class Box.

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

Accessor & Setter methods

In order to use variables outside the class, we must define these variables inside the Accessor method, accessor is actually equivalent to getter. The following example demonstrates the usage of accessor methods:

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造函数
   def initialize(w,h)
      @width, @height = w, h
   end

   # 访问器方法
   def printWidth
      @width
   end

   def printHeight
      @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 使用访问器方法
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 will produce the following results:

Width of the box is : 10
Height of the box is : 20

With the Accessor methods for accessing variable values ​​are similar. Ruby provides a way to set variable values ​​outside the class, which is the so-called setter method, which is defined as follows:

#!/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
   end
end

# 创建对象
box = Box.new(10, 20)

# 使用设置器方法
box.setWidth = 30
box.setHeight = 50

# 使用访问器方法
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 results:

Width of the box is : 30
Height of the box is : 50

Instance method

The definition of instance method is the same as the definition of other methods, using the def keyword, but they can only be accessed through class instances Use, as shown in the example below. Their functionality is not limited to accessing instance variables, but can also do many other tasks according to your needs.

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
a = box.getArea()
puts "Area of the box is : #{a}"


When the above code is executed, it will produce the following results:

Area of the box is : 200

Class Methods & Class Variables

Class variables are variables shared among all instances of a class. In other words, instances of class variables can be accessed by all object instances. Class variables are prefixed with two @ characters (@@) and must be initialized in the class definition, as shown in the following example.

Class methodsUse def self.methodname() to define, class methods end with the end delimiter. Class methods can be called using the form classname.methodname with the class name, as shown in the following example:

#!/usr/bin/ruby -w

class Box
   # 初始化类变量
   @@count = 0
   def initialize(w,h)
      # 给实例变量赋值
      @width, @height = w, h

      @@count += 1
   end

   def self.printCount()
      puts "Box count is : #@@count"
   end
end

# 创建两个对象
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)

# 调用类方法来输出盒子计数
Box.printCount()


When the above code is executed, It produces the following result:

Box count is : 2

to_s method

Any class you define has a to_s instance method that returns a string representation of an object. The following is a simple example that represents a Box object based on width and height:

#!/usr/bin/ruby -w

class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 定义 to_s 方法
   def to_s
      "(w:#@width,h:#@height)"  # 对象的字符串格式
   end
end

# 创建对象
box = Box.new(10, 20)

# 自动调用 to_s 方法
puts "String representation of box is : #{box}"


When the above code is executed, it will produce the following results:

String representation of box is : (w:10,h:20)

Access Control

Ruby provides you with three levels of instance method protection, which are public, private or protected. Ruby does not apply any access control on instance and class variables.

  • Public method: Public method can be called by any object. By default, methods are all public, except the initialize method which is always private.

  • Private Methods: Private methods cannot be accessed or viewed from outside the class. Only class methods can access private members.

  • Protected method: The Protected method can only be called by objects of the class and its subclasses. Access is also only possible within the class and its subclasses.

The following is a simple example demonstrating the syntax of these three modifiers:

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 实例方法默认是 public 的
   def getArea
      getWidth() * getHeight
   end

   # 定义 private 的访问器方法
   def getWidth
      @width
   end
   def getHeight
      @height
   end
   # make them private
   private :getWidth, :getHeight

   # 用于输出面积的实例方法
   def printArea
      @area = getWidth() * getHeight
      puts "Big box area is : #@area"
   end
   # 让实例方法是 protected 的
   protected :printArea
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
a = box.getArea()
puts "Area of the box is : #{a}"

# 尝试调用 protected 的实例方法
box.printArea()


When the above code is executed , it produces the following results. Here, the first method call succeeds, but the second method creates 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

Inheritance is one of the most important concepts in object-oriented programming. Inheritance allows us to define a class based on another class, making it easier to create and maintain applications.

Inheritance helps with code reuse and fast execution. Unfortunately, Ruby does not support multiple inheritance, but Ruby does support mixins. A mixin is like a specific implementation of multiple inheritance, where only the interface part is inheritable.

When creating a class, programmers can directly specify that the new class inherits members of an existing class, so there is no need to write new data members and member functions from scratch. This existing class is called base class or parent class, and the new class is called derived class or subclass.

Ruby also provides the concept of subclassing, which is inheritance. The following example explains this concept. The syntax for extending a class is very simple. Just add a < character and the name of the parent class to the class statement. For example, the following defines class BigBox which is a subclass of Box:

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 定义子类
class BigBox < Box

   # 添加一个新的实例方法
   def printArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# 创建对象
box = BigBox.new(10, 20)

# 输出面积
box.printArea()


When the above code is executed, it will Produces the following result:

Big box area is : 200

Method Overloading

While you can add new functionality in a derived class, sometimes you may want to change the behavior of a method that is already defined in the parent class. At this time, you can keep the method name unchanged and overload the function of the method, as shown in the following example:

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 定义子类
class BigBox < Box

   # 改变已有的 getArea 方法
   def getArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# 创建对象
box = BigBox.new(10, 20)

# 使用重载的方法输出面积
box.getArea()


The output result of the above example is:

Big box area is : 200

Operator overloading

We want to use the + operator to perform vector addition of two Box objects, use the * operator to multiply the width and height of the Box, and use the unary operator - to multiply the width of the Box Negative of height. Here is a version of the Box class with mathematical operator definitions:

class Box
  def initialize(w,h) # 初始化 width 和 height
    @width,@height = w, h
  end

  def +(other)         # 定义 + 来执行向量加法
    Box.new(@width + other.width, @height + other.height)
  end

  def -@               # 定义一元运算符 - 来对 width 和 height 求反
    Box.new(-@width, -@height)
  end

  def *(scalar)        # 执行标量乘法
    Box.new(@width*scalar, @height*scalar)
  end
end

Freezing Objects

Sometimes, we want to prevent an object from being changed. In Object, this is accomplished by the freeze method, which effectively turns an object into a constant. Any object can be frozen by calling Object.freeze. A frozen object cannot be modified, that is, you cannot change its instance variables.

You can check whether a given object has been frozen using the Object.frozen? method. This method returns true if the object has been frozen, otherwise it returns a false value. The following example explains this concept:

#!/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
   end
end

# 创建对象
box = Box.new(10, 20)

# 让我们冻结该对象
box.freeze
if( box.frozen? )
   puts "Box object is frozen object"
else
   puts "Box object is normal object"
end

# 现在尝试使用设置器方法
box.setWidth = 30
box.setHeight = 50

# 使用访问器方法
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 will produce the following results:

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 numerical or string value to a variable. The definition of a constant does not require the use of @ or @@. By convention, constant names are in uppercase letters.

Once a constant is defined, you cannot change its value. You can access the constant directly inside the class just like a variable, but if you want to access the constant outside the class, then you classname::constant must be used, as shown in the example below.

#!/usr/bin/ruby -w

# 定义类
class Box
   BOX_COMPANY = "TATA Inc"
   BOXWEIGHT = 10
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
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 will produce the following results:

Area of the box is : 200
TATA Inc
Box weight is: 10

Class constants can be inherited or overridden like instance methods load.

Use allocate to create objects

There may be a situation where you want to create an object without calling the object constructorinitialize, that is, use the new method to create an object , in which case you can call allocate to create an uninitialized object, as shown in the following example:

#!/usr/bin/ruby -w

# 定义类
class Box
   attr_accessor :width, :height

   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 实例方法
   def getArea
      @width * @height
   end
end

# 使用 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}"


When the above code executes, it produces the following results:

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

Ruby's self and Java's this have similarities, but they are also very different. Java methods are referenced in instance methods, so this generally points to the current object. Ruby's code is executed line by line, so self has different meanings in different contexts. Let’s take a look at the following instance: .

#!/usr/bin/ruby -w

class Box
   # 输出类信息
   puts "Class of self = #{self.class}"
   puts "Name of self = #{self.name}"
end


When the above code is executed, it will produce the following result:

Class of self = Class
Name of self = Box

This means that the class The definition can be executed by making the class the current object, which also means that the method in the metaclass and superclass is available during the execution of the method definition.