📜  Ruby 中的面向对象编程第 2 组

📅  最后修改于: 2022-05-13 01:54:52.195000             🧑  作者: Mango

Ruby 中的面向对象编程第 2 组

先决条件:Ruby 中的面向对象编程 |第一组

遗产

继承是面向对象编程的坚实基本特征之一。有时我们可能需要将一个类的某些特性复制到另一个类中。我们可以从另一个类继承该属性,而不是再次创建该属性。继承自的类称为基类,继承自基类的类称为派生类。

句法 :

class base
# internal data and methods
end
class derived < base
# internal data and methods
end

我们使用<符号进行继承。因此,基类中的所有数据和方法都传递给派生类。然而,这只是一种方式。也就是说,派生类的信息不会被继承回基类,这可以通过一个示例更好地理解,因此请考虑我们的主要示例 Vehicle
让我们以 Vehicle 类作为基类,并创建两个派生类——汽车和巴士。

例子:

# Ruby program of Inheritance
class Vehicle
    def initialize(vehicle_name, vehicle_color)
        @vehicle_name = vehicle_name
        @vehicle_color = vehicle_color
    end
    def description
        puts 'This is a vehicle'
    end
end
  
class Car < Vehicle
    def description
        puts 'This is a car'
    end
  
end 
  
class Bus < Vehicle
    def display_this
        puts 'This is a bus'
    end
  
end  
  
# Creating objects
object1 = Car.new('Nissan', 'red')
object2 = Bus.new('Volvo', 'white')
  
object1.description
object2.description
object2.display_this

输出:

This is a car
This is a vehicle
This is a bus

在上面的例子中,我们有一个基类——Vehicle 和两个派生类——Car 和 Bus。 Car 和 Bus 继承了 Vehicle 类的属性和方法,考虑了 Vehicle 和 Car 通用的方法“Description”,但是它们的功能不同。因此,当 Car 继承 Vehicle 的方法时,它有两个称为 Description 的方法,但这两个方法并不相同,一个是 Car.Description,另一个是 Vehicle.Description。

但是对于 Car 类型的对象,如果我们调用 Description 方法,那么 Car.Description 方法就会执行
因此我们可以说 Car.Description 覆盖 Vehicle.Description。在 Bus 类中,我们只有一个从 Vehicle 类继承的 Description 方法,因此在这种情况下没有覆盖。派生类可以有自己的数据和变量,方法'display_this'就是一个这样的例子。请记住,继承并非相反。因此,如果我们有一个 Vehicle 类型的对象,即object3 = Vehicle.new()那么我们就不能编写object3.display _this 继承只是一种方式。

现在考虑 Car.description 和 Vehicle.Description 这两个 Description 方法的情况。我们说对于 Car 类型的对象,Car.Description 方法将执行,但如果我们希望其他方法 -Vehicle.Description 执行怎么办。为此,我们使用关键字super

# Ruby program of inheritance
class Vehicle
    def initialize(vehicle_name, vehicle_color)
        @vehicle_name = vehicle_name
        @vehicle_color = vehicle_color
    end
    def description
        puts 'This is a vehicle'
    end
end
   
# Using inheritance
class Car < Vehicle
    def description
        puts 'This is a car'
            super
    end
   
end
   
# Using inheritance
class Bus < Vehicle
    def display_this
        puts 'This is a bus'
    end
   
end
  
# creating object
object1 = Car.new('Nissan', 'red')
object2 = Bus.new('Volvo', 'white')
   
# Calling object
object1.description
object2.description
object2.display_this

输出:

This is a car
This is a vehicle
This is a vehicle
This is a bus

与上一个示例相比,此示例的不同之处在于我们在 Car.Description 方法中使用了 super。当我们使用super时,控件回到基类,然后执行基类方法即Vehicle.Description而不是Car.Description。
这就是我们可以重写派生类方法以使用我们的基类方法的方式。

派生类属性

现在假设我们希望我们的派生类有自己的属性。我们仍然需要为基类和派生类传递变量。然后我们使用super调用基类的构造函数,然后我们初始化派生类的属性。
例子 :

# Ruby program of showing Derived class attributes
class Vehicle
    attr_accessor :vehicle_name
    attr_accessor :vehicle_color
    def initialize(vehicle_name, vehicle_color)
        @vehicle_name = vehicle_name
        @vehicle_color = vehicle_color
    end
end
   
class Car < Vehicle
     attr_accessor :car_model
  def initialize(vehicle_name, vehicle_color, car_model)
  
        # Using super keyword
        super(vehicle_name, vehicle_color)
        @car_model = car_model
    end
end
   
# creating object 
object = Car.new('Nissan', 'white', 'xyz')
  
# calling object
puts object.vehicle_name
puts object.vehicle_color
puts object.car_model

输出:

Nissan
white
xyz

我们在派生类 Car 中引入了属性 car_model,同时创建了我们为基类和派生类 (Car) 传递值的对象,因为派生类也具有基类 (Vehicle) 的属性。

从下面的语句中, object = Car.new('Nissan', 'white', 'xyz')控制转到 Car 的初始化方法,从那里我们使用 super 将 Vehicle 属性传递给 Vehicle 的初始化方法,即super(vehicle_name, vehicle_color) 。然后控件传递到vehicle的initialize方法中,然后返回到调用它的地方。然后初始化派生属性,即@car_model = car_model

Ruby 不支持多重继承,因为它经常变得混乱且非常复杂。多重继承是指一个类派生自多个基类。这得到了 C++ 等语言的支持,但它通常被视为过于复杂。但是,我们确实有解决此问题的方法。 Mixins 通常有助于遏制这种缺陷。

公立和私立

默认情况下,如果我们将所有方法都描述为公共的,我们所有的属性和方法都是公共的,它允许我们的方法在我们使用私有的类之外被访问,当我们有我们不想在类外访问的方法时,只有对象是允许从其他公共方法内部使用这些方法。

# Ruby program of Public and Private method
class Vehicle
    def initialize(vehicle_name, vehicle_color)
        @vehicle_name = vehicle_name
        @vehicle_color = vehicle_color
    end
    
  # Using public method
    public
    def display
        greeting
        puts 'Your car details are: '
        puts @vehicle_name
        puts @vehicle_color
    end
    
   # Using Private method
    private
    def greeting
        puts 'Hello, user'
    end
end
  
# Creating object
object = Vehicle.new('Nissan', 'white')
  
# Calling object
object.display

输出:

Hello, user
Your car details are: 
Nissan
white

默认情况下,我们所有的方法都是公共的,所以如果我们希望我们的方法之一是私有的,那么我们应该用关键字private来提及它同样,我们可以使用关键字 as public 将方法称为公共如果我们使用关键字privatepublic之一,然后直到我们再次提及它们,它将保持公共或私有状态,直到类定义结束。

模块

模块就像编码时包含方法甚至常量的代码块,我们可能有很多我们希望使用的工具,但这可能会使整个程序混乱。因此,我们将它们放在模块中,并且仅当我们希望使用其中的方法和常量时才使用模块,它们与类相似,只是我们不能从模块创建对象。

模块语法:

module ModuleName
    #methods and constants
end

模块使用 CapitalizedCamelCase 编写,它只是将模块名称中每个单词的首字母大写,没有空格。

模块示例

module ConstantsAndMethods
    CONST_ONE = 10
    CONST_TWO = 20
    
    def method1
         puts ‘This belongs to ConstantsAndMethods’
    end
end

我们创建了一个名为 ConstantsAndMethods 的模块,我们有两个常量。常量应该在单词之间用大写和下划线书写,我们有一个名为 method1 的方法。要使用模块中的数据和方法,我们使用关键字require 。然后我们可以使用范围解析运算符来访问常量和方法。

require ‘ConstantsAndMethods’

puts ConstantsAndMethods::CONST_ONE

继续我们对模块的介绍,我们现在将了解 mixin。

混合

Mixins 是我们在模块和类之间的交叉点,也是我们解决 Ruby 不允许多重继承问题的方法。我们可以使用关键字include将我们的模块常量和方法包含在我们的类中。

例子 :

# Ruby program of using mixins
module Greeting
    def display
        puts 'Hello'
    end
end
    
class Greetuser
    include Greeting
      attr_reader :name
    def initialize(name)
        @name = name
    end
end
    
# Creating object
object = Greetuser.new('User_name')
  
# Calling object
object.display
puts object.name

输出:

Hello
User_name

我们有一个模块 Greeting 和一个类 Greetuser。正如我们在这一行中看到的object.display我们正在使用类 Greetuser 的对象来使用模块方法 display。我们可以这样做是因为我们在类中进行了包含,即包含问候语。

扩展 Mixin

我们可以使用 extend 代替,不同之处在于 extend 在类级别合并模块
所以类本身可以使用模块方法而不是对象。

例子:

# Ruby program of extending mixins
module Greeting
    def display
        puts 'Hello'
    end
end
  
# Using extend keyword  
class Greetuser
    extend Greeting
  attr_reader :name
    def initialize(name)
        @name = name
    end
end
    
# Creating object
object = Greetuser.new('User_name')
  
# Calling object
Greetuser.display
puts object.name

输出:

Hello
User_name

在前面的示例中,我们将包含替换为扩展。所以现在它实际上是课程的一部分。因此我们可以使用类名Greetuser.display的模块方法