Skip to content

Ruby 类和对象

Ruby是一种纯粹的面向对象编程语言,其中一切都是对象。本章将详细介绍Ruby中的类和对象概念,以及如何使用它们构建程序。

🎯 面向对象基础

什么是类和对象?

  • 类(Class): 对象的模板或蓝图,定义了对象的属性和行为
  • 对象(Object): 类的实例,具有具体的属性值和可以执行的行为
ruby
# 一切都是对象
puts 42.class        # Integer
puts "Hello".class   # String
puts true.class      # TrueClass
puts nil.class       # NilClass

# 查看对象的方法
number = 42
puts number.methods  # 显示所有可用方法

🏗️ 类的定义

基本类定义

ruby
# 定义一个简单的类
class Person
  # 类体
end

# 创建对象(实例化)
person1 = Person.new
person2 = Person.new

puts person1.class  # Person
puts person2.class  # Person
puts person1.object_id  # 对象ID
puts person2.object_id  # 不同的对象ID

构造方法 initialize

ruby
class Person
  # 构造方法(初始化方法)
  def initialize(name, age)
    @name = name  # 实例变量
    @age = age
  end
  
  # 实例方法
  def introduce
    puts "我是#{@name},今年#{@age}岁"
  end
end

# 创建对象并调用方法
person = Person.new("张三", 25)
person.introduce  # 输出: 我是张三,今年25岁

访问器方法

ruby
class Person
  def initialize(name, age)
    @name = name
    @age = age
  end
  
  # getter方法
  def name
    @name
  end
  
  def age
    @age
  end
  
  # setter方法
  def name=(name)
    @name = name
  end
  
  def age=(age)
    @age = age
  end
  
  def introduce
    puts "我是#{@name},今年#{@age}岁"
  end
end

# 使用访问器方法
person = Person.new("李四", 30)
puts person.name    # 李四
person.age = 31
puts person.age     # 31

使用attr_accessor简化访问器

ruby
class Person
  # 自动生成getter和setter方法
  attr_accessor :name, :age
  # 等同于:
  # attr_reader :name, :age  # 只生成getter
  # attr_writer :name, :age  # 只生成setter
  
  def initialize(name, age)
    @name = name
    @age = age
  end
  
  def introduce
    puts "我是#{@name},今年#{@age}岁"
  end
end

# 使用简化访问器
person = Person.new("王五", 28)
puts person.name      # 王五
person.name = "赵六"
person.age = 29
person.introduce      # 我是赵六,今年29岁

📦 变量类型

实例变量

ruby
class Counter
  def initialize
    @count = 0  # 实例变量,以@开头
  end
  
  def increment
    @count += 1
  end
  
  def count
    @count
  end
end

counter1 = Counter.new
counter2 = Counter.new

counter1.increment
counter1.increment
puts counter1.count  # 2
puts counter2.count  # 0 (不同的实例)

类变量

ruby
class Counter
  @@total_instances = 0  # 类变量,以@@开头
  
  def initialize
    @count = 0
    @@total_instances += 1
  end
  
  def increment
    @count += 1
  end
  
  def count
    @count
  end
  
  # 类方法访问类变量
  def self.total_instances
    @@total_instances
  end
end

counter1 = Counter.new
counter2 = Counter.new
counter3 = Counter.new

puts Counter.total_instances  # 3

全局变量

ruby
# 全局变量,以$开头(不推荐大量使用)
$global_counter = 0

class GlobalCounter
  def increment
    $global_counter += 1
  end
  
  def self.global_count
    $global_counter
  end
end

counter = GlobalCounter.new
counter.increment
counter.increment
puts GlobalCounter.global_count  # 2

局部变量和常量

ruby
class MathConstants
  PI = 3.14159  # 常量,大写字母命名
  E = 2.71828
  
  def self.calculate_circle_area(radius)
    local_variable = radius * radius  # 局部变量
    PI * local_variable
  end
end

puts MathConstants::PI  # 3.14159
puts MathConstants.calculate_circle_area(5)  # 78.53975

🎯 方法类型

实例方法

ruby
class Calculator
  def add(a, b)
    a + b
  end
  
  def subtract(a, b)
    a - b
  end
end

calc = Calculator.new
puts calc.add(10, 5)      # 15
puts calc.subtract(10, 5) # 5

类方法

ruby
class MathUtils
  # 方式1: 使用self
  def self.square(number)
    number * number
  end
  
  # 方式2: 使用类名
  def MathUtils.cube(number)
    number * number * number
  end
  
  # 方式3: 在类内部定义
  class << self
    def power(base, exponent)
      base ** exponent
    end
  end
end

puts MathUtils.square(4)    # 16
puts MathUtils.cube(3)      # 27
puts MathUtils.power(2, 3)  # 8

私有方法

ruby
class BankAccount
  def initialize(balance)
    @balance = balance
  end
  
  def deposit(amount)
    if valid_amount?(amount)
      @balance += amount
      puts "存款成功,当前余额: #{@balance}"
    else
      puts "无效金额"
    end
  end
  
  def withdraw(amount)
    if valid_amount?(amount) && sufficient_funds?(amount)
      @balance -= amount
      puts "取款成功,当前余额: #{@balance}"
    else
      puts "取款失败"
    end
  end
  
  def balance
    @balance
  end
  
  private  # 私有方法
  
  def valid_amount?(amount)
    amount > 0
  end
  
  def sufficient_funds?(amount)
    @balance >= amount
  end
end

account = BankAccount.new(1000)
account.deposit(500)    # 存款成功,当前余额: 1500
account.withdraw(200)   # 取款成功,当前余额: 1300
# account.valid_amount?(100)  # 错误: private method

受保护方法

ruby
class Animal
  def initialize(name)
    @name = name
  end
  
  protected  # 受保护方法
  
  def speak
    "#{@name}发出声音"
  end
end

class Dog < Animal
  def initialize(name)
    super(name)
  end
  
  def bark
    speak + " 汪汪!"  # 可以调用父类的受保护方法
  end
end

dog = Dog.new("旺财")
puts dog.bark  # 旺财发出声音 汪汪!
# dog.speak    # 错误: protected method

🧬 继承

基本继承

ruby
# 父类
class Vehicle
  def initialize(brand, model)
    @brand = brand
    @model = model
  end
  
  def start_engine
    puts "#{@brand} #{@model} 引擎启动"
  end
  
  def stop_engine
    puts "#{@brand} #{@model} 引擎关闭"
  end
  
  def info
    "#{@brand} #{@model}"
  end
end

# 子类
class Car < Vehicle
  def initialize(brand, model, doors)
    super(brand, model)  # 调用父类构造方法
    @doors = doors
  end
  
  def open_trunk
    puts "打开后备箱"
  end
  
  # 重写父类方法
  def info
    super + " (#{@doors}门)"
  end
end

# 使用继承
car = Car.new("丰田", "卡罗拉", 4)
car.start_engine     # 丰田 卡罗拉 引擎启动
car.open_trunk       # 打开后备箱
puts car.info        # 丰田 卡罗拉 (4门)

方法查找链

ruby
class A
  def method1
    "A's method1"
  end
end

class B < A
  def method1
    "B's method1"
  end
  
  def method2
    "B's method2"
  end
end

class C < B
  def method1
    "C's method1"
  end
end

obj = C.new
puts obj.method1  # C's method1
puts obj.method2  # B's method2 (继承自B)

🔄 模块和Mixin

模块定义

ruby
# 定义模块
module Flyable
  def fly
    "我在飞翔!"
  end
  
  def land
    "我降落了!"
  end
end

module Swimmable
  def swim
    "我在游泳!"
  end
end

# 使用模块
class Bird
  include Flyable  # 包含模块
end

class Fish
  include Swimmable
end

class Duck
  include Flyable
  include Swimmable
end

bird = Bird.new
puts bird.fly    # 我在飞翔!

duck = Duck.new
puts duck.fly    # 我在飞翔!
puts duck.swim   # 我在游泳!

模块作为命名空间

ruby
module MathUtils
  PI = 3.14159
  
  class Calculator
    def self.add(a, b)
      a + b
    end
  end
  
  def self.square(number)
    number * number
  end
end

puts MathUtils::PI              # 3.14159
puts MathUtils::Calculator.add(2, 3)  # 5
puts MathUtils.square(4)        # 16

🎭 多态性

方法重写和多态

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

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

class Cat < Animal
  def speak
    "喵喵!"
  end
end

class Bird < Animal
  def speak
    "叽叽喳喳!"
  end
end

# 多态性示例
animals = [Dog.new, Cat.new, Bird.new]

animals.each do |animal|
  puts animal.speak  # 根据对象类型调用相应方法
end
# 输出:
# 汪汪!
# 喵喵!
# 叽叽喳喳!

🧱 对象生命周期

初始化和清理

ruby
class Resource
  def initialize(name)
    @name = name
    puts "创建资源: #{@name}"
  end
  
  def use
    puts "使用资源: #{@name}"
  end
  
  # 对象被垃圾回收前调用
  def finalize
    puts "清理资源: #{@name}"
  end
  
  # 自定义析构方法
  def dispose
    puts "手动清理资源: #{@name}"
  end
end

# 对象生命周期
resource = Resource.new("数据库连接")
resource.use
resource.dispose  # 手动清理

# resource变量超出作用域后会被垃圾回收

🎯 高级特性

单例类

ruby
class MyClass
  def instance_method
    "实例方法"
  end
  
  class << self
    def class_method
      "类方法"
    end
  end
end

# 单例方法
obj = MyClass.new

class << obj
  def singleton_method
    "单例方法"
  end
end

puts obj.instance_method    # 实例方法
puts MyClass.class_method   # 类方法
puts obj.singleton_method   # 单例方法

# 检查单例类
puts obj.singleton_class
puts MyClass.singleton_class

方法缺失处理

ruby
class FlexibleObject
  def initialize
    @data = {}
  end
  
  def method_missing(method_name, *args, &block)
    if method_name.to_s.end_with?('=')
      # setter方法
      key = method_name.to_s.chomp('=').to_sym
      @data[key] = args.first
    else
      # getter方法
      @data[method_name]
    end
  end
  
  def respond_to_missing?(method_name, include_private = false)
    true
  end
end

obj = FlexibleObject.new
obj.name = "张三"
obj.age = 25
puts obj.name  # 张三
puts obj.age   # 25

🧪 实践示例

完整的银行账户系统

ruby
class BankAccount
  attr_reader :account_number, :balance
  attr_accessor :owner
  
  @@total_accounts = 0
  
  def initialize(owner, initial_balance = 0)
    @owner = owner
    @balance = initial_balance
    @account_number = generate_account_number
    @@total_accounts += 1
  end
  
  def deposit(amount)
    if amount > 0
      @balance += amount
      log_transaction("存款", amount)
      true
    else
      puts "存款金额必须大于0"
      false
    end
  end
  
  def withdraw(amount)
    if amount > 0 && amount <= @balance
      @balance -= amount
      log_transaction("取款", amount)
      true
    elsif amount > @balance
      puts "余额不足"
      false
    else
      puts "取款金额必须大于0"
      false
    end
  end
  
  def transfer_to(other_account, amount)
    if withdraw(amount)
      other_account.deposit(amount)
      puts "转账成功: #{amount}#{other_account.owner}"
    end
  end
  
  def self.total_accounts
    @@total_accounts
  end
  
  def info
    "账户: #{@account_number}, 户主: #{@owner}, 余额: #{@balance}"
  end
  
  private
  
  def generate_account_number
    "ACC#{rand(100000..999999)}"
  end
  
  def log_transaction(type, amount)
    timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
    puts "[#{timestamp}] #{type}: #{amount}, 余额: #{@balance}"
  end
end

# 使用银行账户系统
account1 = BankAccount.new("张三", 1000)
account2 = BankAccount.new("李四", 500)

puts account1.info
puts account2.info

account1.deposit(200)
account1.withdraw(150)
account1.transfer_to(account2, 300)

puts "总账户数: #{BankAccount.total_accounts}"

🎯 面向对象最佳实践

1. 单一职责原则

ruby
# 好的设计:每个类只有一个职责
class User
  attr_accessor :name, :email
  
  def initialize(name, email)
    @name = name
    @email = email
  end
end

class UserValidator
  def self.valid_email?(email)
    email.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
  end
end

class UserPersistence
  def self.save(user)
    # 保存用户到数据库
  end
end

2. 封装性

ruby
class Temperature
  def initialize(celsius)
    self.celsius = celsius
  end
  
  def celsius
    @celsius
  end
  
  def celsius=(value)
    raise ArgumentError, "温度不能低于绝对零度(-273.15°C)" if value < -273.15
    @celsius = value
  end
  
  def fahrenheit
    @celsius * 9.0 / 5.0 + 32
  end
  
  def fahrenheit=(value)
    self.celsius = (value - 32) * 5.0 / 9.0
  end
end

temp = Temperature.new(25)
puts temp.celsius     # 25
puts temp.fahrenheit  # 77.0
temp.fahrenheit = 86
puts temp.celsius     # 30.0

3. 继承层次设计

ruby
# 抽象基类
class Shape
  def area
    raise NotImplementedError, "子类必须实现area方法"
  end
  
  def perimeter
    raise NotImplementedError, "子类必须实现perimeter方法"
  end
end

class Rectangle < Shape
  def initialize(width, height)
    @width = width
    @height = height
  end
  
  def area
    @width * @height
  end
  
  def perimeter
    2 * (@width + @height)
  end
end

class Circle < Shape
  def initialize(radius)
    @radius = radius
  end
  
  def area
    Math::PI * @radius ** 2
  end
  
  def perimeter
    2 * Math::PI * @radius
  end
end

# 使用多态
shapes = [
  Rectangle.new(5, 3),
  Circle.new(4)
]

shapes.each do |shape|
  puts "面积: #{shape.area.round(2)}, 周长: #{shape.perimeter.round(2)}"
end

📚 下一步学习

掌握了Ruby类和对象后,建议继续学习:

继续您的Ruby学习之旅吧!

本站内容仅供学习和研究使用。