Ruby 属性与方法
本章将介绍 OOP 中的两个基本概念:属性(Attributes)和方法(Methods)。属性定义了对象所持有的数据,而方法定义了对象可以执行的操作。理解如何定义和使用属性与方法,可以创建健壮且易于维护的 Ruby 应用程序。
1. 定义属性
属性是用于保存与对象相关联的数据的变量,它们代表了对象的状态。在 Ruby 中,我们使用 @ 符号加上属性名称(例如 @name,@age)来定义属性。通常,这些属性会在 initialize 方法中被初始化,该方法充当了类的构造函数。
1.1 在 initialize 方法中初始化属性
initialize 是 Ruby 类中的一个特殊方法。当你创建一个类的新实例(对象)时,它会被自动调用。通常,这里就是你设置对象属性初始值的地方。
class Dog
def initialize(name, breed)
@name = name
@breed = breed
end
end
# 创建一个新的 Dog 对象
my_dog = Dog.new("Buddy", "金毛寻回犬")在这个例子中,Dog 类有两个属性:@name 和 @breed。当我们使用 Dog.new("Buddy", "金毛寻回犬") 创建一个新的 Dog 对象时,initialize 方法会被调用,并传入参数 "Buddy" 和 "金毛寻回犬"。随后,这些值被赋给了新 Dog 对象的 @name 和 @breed 属性。
1.2 直接访问属性(不推荐)
虽然在技术上可以通过类似外部调用的方式尝试访问属性,但在 OOP 中,直接在类外部访问内部变量通常被视为一种糟糕的实践。直接访问属性违反了**封装(Encapsulation)**原则,该原则规定对象的内部状态应该对外部世界隐藏。
class Dog
def initialize(name, breed)
@name = name
@breed = breed
end
end
my_dog = Dog.new("Buddy", "金毛寻回犬")
# 避免这样做:
# puts my_dog.name # 这将导致错误,因为在类外部 @name 是私有的(没有读取方法)1.3 使用 attr_reader、attr_writer 和 attr_accessor
为了优雅地控制属性的读取和修改,Ruby 提供了几个非常方便的方法(宏):
attr_reader:为属性创建一个 Getter(读取)方法,允许你读取它的值。attr_writer:为属性创建一个 Setter(写入)方法,允许你更改它的值。attr_accessor:同时为属性创建一个 Getter 和一个 Setter 方法。
class Dog
attr_reader :name, :breed # 为 name 和 breed 创建 Getter (读取) 方法
attr_writer :age # 为 age 创建一个 Setter (写入) 方法
attr_accessor :tricks # 为 tricks 同时创建 Getter 和 Setter 方法
def initialize(name, breed, age)
@name = name
@breed = breed
@age = age
@tricks = [] # 将 tricks 初始化为一个空数组
end
def add_trick(trick)
@tricks << trick
end
end
my_dog = Dog.new("Buddy", "金毛寻回犬", 3)
puts my_dog.name # 访问 name 属性 (调用 Getter)
puts my_dog.breed # 访问 breed 属性 (调用 Getter)
my_dog.age = 4 # 设置 age 属性 (调用 Setter)
# puts my_dog.age # 这一行如果取消注释会导致错误,因为 age 没有 Getter 方法
my_dog.add_trick("接飞盘")
my_dog.add_trick("打滚")
puts my_dog.tricks # 访问 tricks 属性 (调用 Getter)
my_dog.tricks = ["装死"]
puts my_dog.tricks # 在使用 Setter 修改后,再次访问 tricks 属性 (调用 Getter)在这个例子中:
attr_reader :name, :breed创建了name和breed方法,分别返回@name和@breed的值。你可以读取这些属性,但无法从类外部直接修改它们。attr_writer :age创建了一个age=方法,允许你从类外部更改@age的值,但你仍然无法直接读取它。attr_accessor :tricks同时创建了读取方法tricks和写入方法tricks=。你可以从类外部自由地读取和修改@tricks的值。
2. 定义方法
方法定义了对象的行为——即它可以执行的操作。方法使用 def 关键字来定义,紧接着是方法名、该方法接收的任何参数,以及方法主体。
2.1 实例方法 (Instance Methods)
实例方法是在类的特定实例(对象)上运行的方法。它们可以访问该对象的属性,并可以修改对象的状态。
class Dog
attr_reader :name, :breed
attr_accessor :age, :tricks
def initialize(name, breed, age)
@name = name
@breed = breed
@age = age
@tricks = []
end
def bark
puts "汪汪!"
end
def introduce
puts "你好,我的名字是 #{@name},我是一只 #{@breed}。"
end
def add_trick(trick)
@tricks << trick
end
end
my_dog = Dog.new("Buddy", "金毛寻回犬", 3)
my_dog.bark # 调用 bark 方法
my_dog.introduce # 调用 introduce 方法
my_dog.add_trick("接飞盘") # 调用 add_trick 方法
puts my_dog.tricks在这个例子中:
bark是一个让狗叫的方法。它只是简单地在控制台打印 "汪汪!"。introduce是一个介绍狗的方法,它使用了狗的@name和@breed属性。add_trick是一个向狗的@tricks数组中添加技能的方法。
2.2 方法参数与返回值
方法可以接收参数(即调用方法时传递给它的值)。方法也可以返回值(即方法执行完毕后的结果)。
class Dog
attr_reader :name, :breed
attr_accessor :age, :tricks
def initialize(name, breed, age)
@name = name
@breed = breed
@age = age
@tricks = []
end
# human_years_factor 有一个默认值 7
def age_in_human_years(human_years_factor = 7)
@age * human_years_factor # 隐式返回计算结果
end
end
my_dog = Dog.new("Buddy", "金毛寻回犬", 3)
human_age = my_dog.age_in_human_years # 使用默认的乘数 (7) 调用方法
puts human_age
human_age = my_dog.age_in_human_years(5) # 使用自定义的乘数 (5) 调用方法
puts human_age在这个例子中:
age_in_human_years是一个计算狗“相当于人类年龄”的方法。它接收一个可选参数human_years_factor,默认值为 7。该方法会隐式返回计算后的年龄值。
3. 真实世界应用案例
想象一个构建电子商务应用程序的场景。你可能需要一个 Product(产品)类。
class Product
attr_reader :name, :price
attr_accessor :quantity
def initialize(name, price, quantity)
@name = name
@price = price
@quantity = quantity
end
def is_available?
@quantity > 0
end
def purchase(amount)
if is_available? && @quantity >= amount
@quantity -= amount
puts "成功购买了 #{amount} 件 #{@name}。"
else
puts "抱歉,#{@name} 库存不足。"
end
end
end
product = Product.new("T恤", 20, 50)
puts product.is_available? # 检查是否可用
product.purchase(2) # 购买 2 件
puts product.quantity # 检查剩余库存
product.purchase(51) # 尝试购买超过库存的数量在这里,诸如 name、price 和 quantity 等属性定义了产品的状态。而诸如 is_available? 和 purchase 等方法定义了产品的行为。这完美地展示了属性和方法是如何在面向对象编程中,模拟现实世界实体的基础。