MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Ruby 面向对象编程入门

2024-12-072.3k 阅读

面向对象编程基础概念

在深入 Ruby 的面向对象编程之前,让我们先回顾一些基本概念。面向对象编程(OOP)是一种编程范式,它将程序组织成一组相互协作的对象,每个对象都代表现实世界中的某个实体或概念。在 OOP 中,主要有以下几个核心概念:

类(Class)

类是对象的蓝图或模板。它定义了对象的属性(数据)和方法(行为)。例如,我们要创建一个 “人” 的类,类中可能会有姓名、年龄等属性,以及说话、走路等方法。在 Ruby 中,定义一个类的语法如下:

class Person
  # 这里可以定义属性和方法
end

对象(Object)

对象是类的实例。根据 “人” 这个类,我们可以创建出具体的某个人,比如 “张三”“李四” 等,这些具体的人就是对象。在 Ruby 中,可以使用 new 方法来创建对象:

class Person
end

person1 = Person.new

属性(Attribute)

属性是对象所具有的数据。以 “人” 类为例,姓名、年龄就是属性。在 Ruby 中,可以通过实例变量来表示属性。实例变量以 @ 符号开头,例如:

class Person
  def initialize(name, age)
    @name = name
    @age = age
  end
end

person1 = Person.new('张三', 25)

在上面的代码中,@name@age 就是 Person 对象的属性,通过 initialize 方法在创建对象时进行初始化。

方法(Method)

方法是对象能够执行的操作或行为。还是以 “人” 类为例,说话、走路等就是方法。在 Ruby 中定义方法的语法如下:

class Person
  def speak
    puts "我叫 #{@name},今年 #{@age} 岁。"
  end
end

person1 = Person.new('张三', 25)
person1.speak

上述代码中,speak 方法就是 Person 类的一个方法,它使用了对象的属性 @name@age 来输出信息。

Ruby 中的类定义

基本类定义

在 Ruby 中,定义一个类非常简单,使用 class 关键字,后面跟上类名,类名通常采用驼峰命名法(CamelCase)。类的定义以 end 关键字结束。例如,定义一个简单的 Dog 类:

class Dog
  def bark
    puts "汪汪汪!"
  end
end

在这个 Dog 类中,我们定义了一个 bark 方法,当调用这个方法时,会输出 “汪汪汪!”。

初始化方法(initialize)

初始化方法是一个特殊的方法,当使用 new 方法创建对象时,会自动调用这个方法。它通常用于设置对象的初始状态,比如初始化属性。以下是在 Dog 类中添加初始化方法的示例:

class Dog
  def initialize(name, breed)
    @name = name
    @breed = breed
  end

  def bark
    puts "#{@name}(#{@breed})汪汪汪!"
  end
end

dog1 = Dog.new('小白', '博美')
dog1.bark

在上述代码中,initialize 方法接受两个参数 namebreed,并将它们分别赋值给实例变量 @name@breedbark 方法则使用这些属性来输出更详细的信息。

类变量和类方法

类变量是属于类本身的变量,而不是属于类的实例(对象)。类变量以 @@ 符号开头。类方法是定义在类上而不是对象上的方法。以下是一个包含类变量和类方法的示例:

class Dog
  @@total_dogs = 0

  def initialize(name, breed)
    @name = name
    @breed = breed
    @@total_dogs += 1
  end

  def bark
    puts "#{@name}(#{@breed})汪汪汪!"
  end

  def self.total_dogs
    @@total_dogs
  end
end

dog1 = Dog.new('小白', '博美')
dog2 = Dog.new('小黑', '拉布拉多')

puts "总共有 #{Dog.total_dogs} 只狗。"

在这个例子中,@@total_dogs 是类变量,用于统计创建的 Dog 对象的总数。self.total_dogs 是类方法,用于获取类变量的值。

Ruby 中的对象

创建对象

正如前面所提到的,在 Ruby 中使用 new 方法来创建对象。例如,创建一个 Car 类的对象:

class Car
  def initialize(model, color)
    @model = model
    @color = color
  end

  def info
    puts "这是一辆 #{@color} 颜色的 #{@model} 汽车。"
  end
end

car1 = Car.new('奔驰 C 级', '黑色')
car1.info

上述代码创建了一个 Car 类的对象 car1,并调用了 info 方法来输出汽车的信息。

对象的属性访问

在 Ruby 中,我们可以通过访问器方法(getter 和 setter 方法)来访问和修改对象的属性。

  • Getter 方法:用于获取属性的值。我们可以手动定义,也可以使用 attr_reader 来自动生成。例如:
class Person
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

person1 = Person.new('张三')
puts person1.name

在上述代码中,attr_reader :name 自动生成了一个 name 方法,用于获取 @name 的值。

  • Setter 方法:用于设置属性的值。同样,可以手动定义,也可以使用 attr_writer 来自动生成。例如:
class Person
  attr_writer :name

  def initialize
    @name = nil
  end
end

person1 = Person.new
person1.name = '李四'

在上述代码中,attr_writer :name 自动生成了一个 name= 方法,用于设置 @name 的值。

如果既需要获取又需要设置属性的值,可以使用 attr_accessor,它同时生成 getter 和 setter 方法:

class Person
  attr_accessor :name

  def initialize
    @name = nil
  end
end

person1 = Person.new
person1.name = '王五'
puts person1.name

继承

继承的概念

继承是面向对象编程中的一个重要概念,它允许一个类(子类)从另一个类(父类)中获取属性和方法。子类可以复用父类的代码,并且可以根据需要添加或修改自己的属性和方法。在 Ruby 中,使用 < 符号来表示继承关系。例如:

class Animal
  def speak
    puts "动物发出声音。"
  end
end

class Dog < Animal
  def bark
    puts "汪汪汪!"
  end
end

dog1 = Dog.new
dog1.speak
dog1.bark

在上述代码中,Dog 类继承自 Animal 类,所以 Dog 对象可以调用 Animal 类的 speak 方法,同时也有自己的 bark 方法。

重写方法

子类可以重写父类的方法,以提供更具体或不同的实现。例如:

class Animal
  def speak
    puts "动物发出声音。"
  end
end

class Dog < Animal
  def speak
    puts "汪汪汪!"
  end
end

dog1 = Dog.new
dog1.speak

在这个例子中,Dog 类重写了 Animal 类的 speak 方法,当调用 dog1.speak 时,会执行 Dog 类中重写后的方法。

super 关键字

在子类重写父类方法时,如果需要调用父类的方法,可以使用 super 关键字。例如:

class Animal
  def speak
    puts "动物发出声音。"
  end
end

class Dog < Animal
  def speak
    super
    puts "汪汪汪!"
  end
end

dog1 = Dog.new
dog1.speak

在上述代码中,Dog 类的 speak 方法先调用了父类的 speak 方法(通过 super),然后再输出 “汪汪汪!”。

多态

多态的概念

多态是指同一个方法调用,在不同的对象上会有不同的行为。这是通过继承和方法重写来实现的。例如,我们有一个 Shape 类,以及它的子类 CircleRectangle,每个子类都有自己的 area 方法实现:

class Shape
  def area
    raise NotImplementedError, "子类必须实现 area 方法"
  end
end

class Circle < Shape
  def initialize(radius)
    @radius = radius
  end

  def area
    Math::PI * @radius * @radius
  end
end

class Rectangle < Shape
  def initialize(width, height)
    @width = width
    @height = height
  end

  def area
    @width * @height
  end
end

shapes = [Circle.new(5), Rectangle.new(4, 6)]
shapes.each do |shape|
  puts "面积是 #{shape.area}"
end

在上述代码中,shapes 数组包含了 CircleRectangle 对象,当调用 shape.area 时,会根据对象的实际类型(CircleRectangle)来调用相应的 area 方法,这就是多态的体现。

封装

封装的概念

封装是将数据和操作数据的方法包装在一起,对外隐藏对象的内部实现细节,只提供必要的接口来与对象进行交互。在 Ruby 中,通过访问控制符来实现一定程度的封装。

访问控制符

  • public:公共方法,可以在任何地方调用。默认情况下,Ruby 中的方法都是 public 的。例如:
class Person
  def speak
    puts "我在说话。"
  end
end

person1 = Person.new
person1.speak
  • private:私有方法,只能在对象内部调用,不能从外部调用。可以使用 private 关键字来声明私有方法。例如:
class Person
  def speak
    puts "我在说话。"
    private_method
  end

  private
  def private_method
    puts "这是私有方法。"
  end
end

person1 = Person.new
person1.speak
# person1.private_method  # 这行代码会报错,因为不能从外部调用私有方法
  • protected:受保护方法,只能在对象内部以及子类对象内部调用。可以使用 protected 关键字来声明受保护方法。例如:
class Animal
  protected
  def protected_method
    puts "这是受保护方法。"
  end
end

class Dog < Animal
  def bark
    protected_method
  end
end

dog1 = Dog.new
dog1.bark
# Animal.new.protected_method  # 这行代码会报错,因为不能从外部调用受保护方法

模块(Module)

模块的概念

模块是一种组织代码的方式,它可以包含方法、常量等。与类不同的是,模块不能实例化,它主要用于提供可复用的代码片段,避免命名冲突,以及实现混入(mixin)功能。

定义模块

在 Ruby 中,使用 module 关键字来定义模块,模块名通常采用大写字母开头的驼峰命名法。模块的定义以 end 关键字结束。例如:

module Utility
  def self.square(x)
    x * x
  end
end

result = Utility.square(5)
puts result

在上述代码中,Utility 模块定义了一个类方法 square,可以通过模块名来调用这个方法。

混入(Mixin)

混入是指将模块中的方法添加到类中,使得类可以使用模块中的方法。在 Ruby 中,使用 include 关键字来实现混入。例如:

module Flyable
  def fly
    puts "我在飞。"
  end
end

class Bird
  include Flyable
end

bird1 = Bird.new
bird1.fly

在上述代码中,Bird 类通过 include FlyableFlyable 模块混入,从而 Bird 对象可以调用 fly 方法。

总结

通过以上内容,我们对 Ruby 的面向对象编程有了较为深入的了解。从类和对象的基本概念,到继承、多态、封装等重要特性,再到模块的使用,这些知识构成了 Ruby 面向对象编程的核心。掌握这些内容,将有助于我们编写更加结构化、可维护和可复用的 Ruby 代码,无论是开发小型脚本还是大型应用程序,都能得心应手。希望大家在实践中不断探索和运用这些知识,提升自己的编程能力。