name: ruby-oop user-invocable: false description: 当处理Ruby的面向对象编程特性时使用,包括类、模块、继承、混入和方法可见性。 allowed-tools:
- Bash
- Read
- Write
- Edit
Ruby 面向对象编程
掌握Ruby优雅的面向对象编程特性。Ruby是一种纯面向对象语言,其中一切都是对象。
类定义
基本类结构
class Person
# 类变量(在所有实例间共享)
@@count = 0
# 常量
MAX_AGE = 150
# 类方法
def self.count
@@count
end
# 构造函数
def initialize(name, age)
@name = name # 实例变量
@age = age
@@count += 1
end
# 实例方法
def introduce
"Hi, I'm #{@name} and I'm #{@age} years old"
end
# 属性访问器(getter和setter)
attr_accessor :name
attr_reader :age # 只读
attr_writer :email # 只写
end
person = Person.new("Alice", 30)
puts person.introduce
person.name = "Alicia"
方法可见性
class BankAccount
def initialize(balance)
@balance = balance
end
# 公共方法(默认)
def deposit(amount)
@balance += amount
log_transaction(:deposit, amount)
end
def balance
format_currency(@balance)
end
# 受保护方法 - 可由同一类或子类的实例调用
protected
def log_transaction(type, amount)
puts "[#{type}] #{amount}"
end
# 私有方法 - 仅在此实例内可调用
private
def format_currency(amount)
"$#{amount}"
end
end
继承
单继承
class Animal
def initialize(name)
@name = name
end
def speak
"Some sound"
end
end
class Dog < Animal
def speak
"Woof! My name is #{@name}"
end
# 使用super调用父类方法
def introduce
super # 调用父类的speak方法
puts "I'm a dog"
end
end
dog = Dog.new("Buddy")
puts dog.speak
方法重写和Super
class Vehicle
def initialize(brand)
@brand = brand
end
def start_engine
puts "Engine starting..."
end
end
class Car < Vehicle
def initialize(brand, model)
super(brand) # 调用父类构造函数
@model = model
end
def start_engine
super # 调用父类方法
puts "#{@brand} #{@model} is ready to drive"
end
end
模块和混入
模块作为命名空间
module MyApp
module Utils
def self.format_date(date)
date.strftime("%Y-%m-%d")
end
end
end
MyApp::Utils.format_date(Time.now)
模块作为混入
module Swimmable
def swim
"I'm swimming!"
end
end
module Flyable
def fly
"I'm flying!"
end
end
class Duck
include Swimmable # 添加为实例方法
include Flyable
def quack
"Quack!"
end
end
duck = Duck.new
puts duck.swim
puts duck.fly
Extend vs Include
module Greetable
def greet
"Hello!"
end
end
class Person
include Greetable # 添加为实例方法
end
class Company
extend Greetable # 添加为类方法
end
Person.new.greet # 有效
Company.greet # 有效
高级OOP模式
单例模式
class Database
@instance = nil
private_class_method :new
def self.instance
@instance ||= new
end
def connect
puts "Connected to database"
end
end
db1 = Database.instance
db2 = Database.instance
db1.object_id == db2.object_id # true
方法缺失(动态方法)
class DynamicAttributes
def method_missing(method_name, *args)
attribute = method_name.to_s
if attribute.end_with?("=")
# Setter
instance_variable_set("@#{attribute.chop}", args.first)
else
# Getter
instance_variable_get("@#{attribute}")
end
end
def respond_to_missing?(method_name, include_private = false)
true
end
end
obj = DynamicAttributes.new
obj.name = "Ruby"
puts obj.name # "Ruby"
类实例变量
class Product
@inventory = []
class << self
attr_accessor :inventory
def add(product)
@inventory << product
end
end
end
Product.add("Laptop")
Struct和OpenStruct
Struct(近似不可变)
Person = Struct.new(:name, :age) do
def introduce
"I'm #{name}, #{age} years old"
end
end
person = Person.new("Bob", 25)
puts person.name
person.age = 26
OpenStruct(动态属性)
require 'ostruct'
person = OpenStruct.new
person.name = "Charlie"
person.age = 30
person.email = "charlie@example.com"
puts person.name
组合优于继承
class Engine
def start
"Engine started"
end
end
class Wheels
def rotate
"Wheels rotating"
end
end
class Car
def initialize
@engine = Engine.new
@wheels = Wheels.new
end
def start
@engine.start
end
def drive
@wheels.rotate
end
end
Comparable和Enumerable
使类可比较
class Person
include Comparable
attr_reader :age
def initialize(name, age)
@name = name
@age = age
end
def <=>(other)
age <=> other.age
end
end
people = [Person.new("Alice", 30), Person.new("Bob", 25)]
puts people.sort.map(&:age) # [25, 30]
类变量 vs 实例变量
class Counter
@@count = 0 # 类变量(共享)
@instances = [] # 类实例变量(不与子类共享)
def initialize
@@count += 1
end
def self.count
@@count
end
end
最佳实践
- 优先使用组合而非继承 处理复杂关系
- 使用模块进行混入 在不相关的类之间共享行为
- 保持类小而专注(单一职责原则)
- 使用attr_accessor/reader/writer 代替手动getter/setter
- 利用private/protected 封装实现细节
- 优先使用实例变量 而非类变量,以避免意外共享
- 使用Struct处理简单数据对象 而非完整类
- 重写to_s以进行调试 提供有意义的字符串表示
反模式
❌ 不要不必要地使用类变量 - 它们在继承层次结构中共享 ❌ 不要创建上帝对象 - 保持类专注且小 ❌ 不要暴露内部状态 - 使用方法而非直接实例变量访问 ❌ 不要过度使用继承 - 优先使用组合或模块 ❌ 不要忽略可见性修饰符 - 它们用于封装
相关技能
- ruby-metaprogramming - 用于动态类/方法生成
- ruby-blocks-procs-lambdas - 用于函数式编程模式
- ruby-modules - 用于高级模块使用