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 将方法称为公共如果我们使用关键字private或public之一,然后直到我们再次提及它们,它将保持公共或私有状态,直到类定义结束。
模块
模块就像编码时包含方法甚至常量的代码块,我们可能有很多我们希望使用的工具,但这可能会使整个程序混乱。因此,我们将它们放在模块中,并且仅当我们希望使用其中的方法和常量时才使用模块,它们与类相似,只是我们不能从模块创建对象。
模块语法:
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
的模块方法