Ruby多态 #

一、多态概述 #

多态是指同一操作作用于不同对象时产生不同行为。Ruby通过鸭子类型实现多态。

二、鸭子类型 #

2.1 基本概念 #

“如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。”

ruby
class Duck
  def quack
    "Quack!"
  end
end

class Person
  def quack
    "I'm pretending to be a duck!"
  end
end

def make_it_quack(duck)
  duck.quack
end

make_it_quack(Duck.new)
make_it_quack(Person.new)

2.2 类型检查 vs 鸭子类型 #

ruby
def process_wrong(obj)
  raise TypeError unless obj.is_a?(String)
  obj.upcase
end

def process_right(obj)
  obj.upcase
end

process_right("hello")
process_right(:hello)

2.3 respond_to? #

ruby
def safe_quack(obj)
  if obj.respond_to?(:quack)
    obj.quack
  else
    "Cannot quack"
  end
end

三、方法重写多态 #

3.1 基本用法 #

ruby
class Animal
  def speak
    "Some sound"
  end
end

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

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

def make_sound(animal)
  animal.speak
end

make_sound(Dog.new)
make_sound(Cat.new)

3.2 数组多态 #

ruby
animals = [Dog.new, Cat.new, Animal.new]
animals.map(&:speak)

四、接口模式 #

4.1 模块接口 #

ruby
module Drawable
  def draw
    raise NotImplementedError
  end
end

class Circle
  include Drawable

  def draw
    "Drawing circle"
  end
end

class Square
  include Drawable

  def draw
    "Drawing square"
  end
end

def render(drawable)
  drawable.draw
end

4.2 抽象基类 #

ruby
class Shape
  def area
    raise NotImplementedError
  end

  def perimeter
    raise NotImplementedError
  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

五、策略模式 #

5.1 基本实现 #

ruby
class PaymentProcessor
  def initialize(strategy)
    @strategy = strategy
  end

  def process(amount)
    @strategy.pay(amount)
  end
end

class CreditCardPayment
  def pay(amount)
    "Paid #{amount} via Credit Card"
  end
end

class PayPalPayment
  def pay(amount)
    "Paid #{amount} via PayPal"
  end
end

processor = PaymentProcessor.new(CreditCardPayment.new)
processor.process(100)

processor = PaymentProcessor.new(PayPalPayment.new)
processor.process(100)

5.2 使用Lambda #

ruby
class Calculator
  STRATEGIES = {
    add: ->(a, b) { a + b },
    subtract: ->(a, b) { a - b },
    multiply: ->(a, b) { a * b }
  }

  def calculate(operation, a, b)
    STRATEGIES[operation].call(a, b)
  end
end

calc = Calculator.new
calc.calculate(:add, 5, 3)
calc.calculate(:multiply, 5, 3)

六、实用示例 #

6.1 文件处理器 #

ruby
class FileHandler
  def initialize(parser)
    @parser = parser
  end

  def process(file)
    data = read(file)
    @parser.parse(data)
  end

  private

  def read(file)
    File.read(file)
  end
end

class JSONParser
  def parse(data)
    JSON.parse(data)
  end
end

class XMLParser
  def parse(data)
    Nokogiri::XML(data)
  end
end

class CSVParser
  def parse(data)
    CSV.parse(data)
  end
end

6.2 通知系统 #

ruby
class Notifier
  def initialize(channels)
    @channels = channels
  end

  def notify(message)
    @channels.each { |channel| channel.send(message) }
  end
end

class EmailChannel
  def send(message)
    puts "Email: #{message}"
  end
end

class SMSChannel
  def send(message)
    puts "SMS: #{message}"
  end
end

class PushChannel
  def send(message)
    puts "Push: #{message}"
  end
end

notifier = Notifier.new([EmailChannel.new, SMSChannel.new, PushChannel.new])
notifier.notify("Hello!")

6.3 排序策略 #

ruby
class Sorter
  def initialize(strategy)
    @strategy = strategy
  end

  def sort(items)
    items.sort(&@strategy)
  end
end

by_name = Sorter.new(->(a, b) { a[:name] <=> b[:name] })
by_age = Sorter.new(->(a, b) { a[:age] <=> b[:age] })

people = [
  { name: "Bob", age: 30 },
  { name: "Alice", age: 25 },
  { name: "Charlie", age: 35 }
]

by_name.sort(people)
by_age.sort(people)

6.4 数据导出 #

ruby
class DataExporter
  def initialize(formatter)
    @formatter = formatter
  end

  def export(data)
    @formatter.format(data)
  end
end

class JSONFormatter
  def format(data)
    JSON.generate(data)
  end
end

class CSVFormatter
  def format(data)
    data.map(&:to_csv).join("\n")
  end
end

class XMLFormatter
  def format(data)
    data.to_xml
  end
end

七、多态最佳实践 #

7.1 依赖接口而非实现 #

ruby
def process_wrong(obj)
  raise TypeError unless obj.is_a?(MyClass)
  obj.do_something
end

def process_right(obj)
  obj.do_something
end

7.2 使用respond_to?检查 #

ruby
def safe_process(obj)
  if obj.respond_to?(:required_method)
    obj.required_method
  else
    handle_missing_method(obj)
  end
end

7.3 小对象组合 #

ruby
class ReportGenerator
  def initialize(formatter, exporter)
    @formatter = formatter
    @exporter = exporter
  end

  def generate(data)
    formatted = @formatter.format(data)
    @exporter.export(formatted)
  end
end

八、总结 #

本章我们学习了:

  1. 鸭子类型:基于行为而非类型
  2. 方法重写:子类多态
  3. 接口模式:模块接口、抽象基类
  4. 策略模式:运行时切换行为
  5. 实用示例:文件处理、通知系统、数据导出
  6. 最佳实践:依赖接口、使用respond_to?、组合对象

接下来让我们学习Ruby的特殊方法!

最后更新:2026-03-27