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

Ruby中的设计模式应用案例解析

2024-12-313.2k 阅读

单例模式在 Ruby 中的应用

单例模式是一种创建型设计模式,它确保一个类仅有一个实例,并提供一个全局访问点。在 Ruby 中,实现单例模式有多种方式。

使用 Singleton 模块

Ruby 标准库提供了 Singleton 模块,使用它可以很方便地将一个类变成单例类。

require 'singleton'

class DatabaseConnection
  include Singleton

  def connect
    puts "Connecting to the database..."
  end
end

# 使用单例实例
connection1 = DatabaseConnection.instance
connection2 = DatabaseConnection.instance

puts connection1.object_id == connection2.object_id # 输出 true
connection1.connect

在上述代码中,通过 include SingletonDatabaseConnection 类变成了单例类。instance 方法用于获取该单例类的唯一实例。无论调用多少次 instance 方法,返回的都是同一个对象,这通过比较两个实例的 object_id 可以验证。

手动实现单例模式

不依赖 Singleton 模块,也可以手动实现单例模式。

class Logger
  def self.instance
    @instance ||= new
    @instance
  end

  private_class_method :new

  def log(message)
    puts "[#{Time.now}] #{message}"
  end
end

# 使用单例实例
logger1 = Logger.instance
logger2 = Logger.instance

puts logger1.object_id == logger2.object_id # 输出 true
logger1.log("This is a log message")

这里,通过定义一个类方法 instance,在方法中使用 @instance ||= new 来确保只有一个实例被创建。同时,通过 private_class_method :new 防止外部直接调用 new 方法创建新的实例。

工厂模式在 Ruby 中的应用

工厂模式是一种创建型设计模式,它提供了一种创建对象的方式,将对象的创建和使用分离。

简单工厂模式

简单工厂模式定义了一个工厂类,用于创建产品对象。

class Animal
  def speak
    raise NotImplementedError, "Subclasses must implement #speak"
  end
end

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

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

class AnimalFactory
  def self.create_animal(type)
    case type
    when 'dog'
      Dog.new
    when 'cat'
      Cat.new
    else
      raise ArgumentError, "Unsupported animal type: #{type}"
    end
  end
end

# 使用工厂创建动物
dog = AnimalFactory.create_animal('dog')
cat = AnimalFactory.create_animal('cat')

puts dog.speak # 输出 Woof!
puts cat.speak # 输出 Meow!

在这段代码中,AnimalFactory 类是工厂类,create_animal 方法根据传入的类型参数创建相应的动物对象。这样,对象的创建逻辑集中在工厂类中,使用方只需要调用工厂方法获取对象,而不需要关心对象的具体创建过程。

工厂方法模式

工厂方法模式将对象的创建延迟到子类中实现。

class Shape
  def draw
    raise NotImplementedError, "Subclasses must implement #draw"
  end
end

class Circle < Shape
  def draw
    puts "Drawing a circle"
  end
end

class Rectangle < Shape
  def draw
    puts "Drawing a rectangle"
  end
end

class ShapeFactory
  def create_shape
    raise NotImplementedError, "Subclasses must implement #create_shape"
  end
end

class CircleFactory < ShapeFactory
  def create_shape
    Circle.new
  end
end

class RectangleFactory < ShapeFactory
  def create_shape
    Rectangle.new
  end
end

# 使用工厂创建形状
circle_factory = CircleFactory.new
circle = circle_factory.create_shape
circle.draw # 输出 Drawing a circle

rectangle_factory = RectangleFactory.new
rectangle = rectangle_factory.create_shape
rectangle.draw # 输出 Drawing a rectangle

这里,ShapeFactory 是抽象工厂类,定义了 create_shape 抽象方法。CircleFactoryRectangleFactory 是具体的工厂子类,分别实现 create_shape 方法来创建具体的形状对象。通过这种方式,不同类型对象的创建逻辑分布在不同的工厂子类中,增加了代码的可扩展性。

策略模式在 Ruby 中的应用

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。

class PaymentStrategy
  def pay(amount)
    raise NotImplementedError, "Subclasses must implement #pay"
  end
end

class CreditCardPayment < PaymentStrategy
  def initialize(card_number, expiration, cvv)
    @card_number = card_number
    @expiration = expiration
    @cvv = cvv
  end

  def pay(amount)
    puts "Paying $#{amount} with credit card #{@card_number} (expires #{@expiration}, CVV #{@cvv})"
  end
end

class PayPalPayment < PaymentStrategy
  def initialize(email)
    @email = email
  end

  def pay(amount)
    puts "Paying $#{amount} with PayPal account #{@email}"
  end
end

class Order
  def initialize(payment_strategy)
    @payment_strategy = payment_strategy
  end

  def checkout(amount)
    @payment_strategy.pay(amount)
  end
end

# 使用不同的支付策略
credit_card = CreditCardPayment.new('1234567890123456', '12/25', '123')
paypal = PayPalPayment.new('user@example.com')

order1 = Order.new(credit_card)
order1.checkout(100) # 输出 Paying $100 with credit card 1234567890123456 (expires 12/25, CVV 123)

order2 = Order.new(paypal)
order2.checkout(200) # 输出 Paying $200 with PayPal account user@example.com

在上述代码中,PaymentStrategy 是抽象策略类,定义了 pay 抽象方法。CreditCardPaymentPayPalPayment 是具体的策略子类,实现了 pay 方法。Order 类接受一个支付策略对象,并在 checkout 方法中调用该策略的 pay 方法进行支付。这样,不同的支付策略可以方便地替换,而 Order 类的代码不需要修改。

观察者模式在 Ruby 中的应用

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,会通知所有观察者对象,使它们能够自动更新。

class Subject
  def initialize
    @observers = []
  end

  def attach(observer)
    @observers << observer
  end

  def detach(observer)
    @observers.delete(observer)
  end

  def notify
    @observers.each do |observer|
      observer.update(self)
    end
  end
end

class Observer
  def update(subject)
    raise NotImplementedError, "Subclasses must implement #update"
  end
end

class ConcreteSubject < Subject
  def initialize
    super
    @state = nil
  end

  def state=(new_state)
    @state = new_state
    notify
  end

  def state
    @state
  end
end

class ConcreteObserver < Observer
  def initialize(name)
    @name = name
  end

  def update(subject)
    puts "#{@name} observed a state change: #{subject.state}"
  end
end

# 使用观察者模式
subject = ConcreteSubject.new
observer1 = ConcreteObserver.new('Observer 1')
observer2 = ConcreteObserver.new('Observer 2')

subject.attach(observer1)
subject.attach(observer2)

subject.state = 'new state'
# 输出 Observer 1 observed a state change: new state
# 输出 Observer 2 observed a state change: new state

在这段代码中,Subject 类是主题类,维护了一个观察者列表,并提供了添加、移除观察者和通知观察者的方法。Observer 类是抽象观察者类,定义了 update 抽象方法。ConcreteSubject 是具体主题类,当 state 发生变化时会通知观察者。ConcreteObserver 是具体观察者类,实现了 update 方法来处理主题状态变化的通知。

装饰器模式在 Ruby 中的应用

装饰器模式是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。

class Beverage
  def cost
    raise NotImplementedError, "Subclasses must implement #cost"
  end

  def description
    raise NotImplementedError, "Subclasses must implement #description"
  end
end

class Coffee < Beverage
  def cost
    2.0
  end

  def description
    'Coffee'
  end
end

class MilkDecorator < Beverage
  def initialize(beverage)
    @beverage = beverage
  end

  def cost
    @beverage.cost + 0.5
  end

  def description
    "#{@beverage.description}, with milk"
  end
end

class SugarDecorator < Beverage
  def initialize(beverage)
    @beverage = beverage
  end

  def cost
    @beverage.cost + 0.2
  end

  def description
    "#{@beverage.description}, with sugar"
  end
end

# 使用装饰器模式
coffee = Coffee.new
puts "Cost: #{coffee.cost}, Description: #{coffee.description}" # 输出 Cost: 2.0, Description: Coffee

coffee_with_milk = MilkDecorator.new(coffee)
puts "Cost: #{coffee_with_milk.cost}, Description: #{coffee_with_milk.description}" # 输出 Cost: 2.5, Description: Coffee, with milk

coffee_with_milk_and_sugar = SugarDecorator.new(coffee_with_milk)
puts "Cost: #{coffee_with_milk_and_sugar.cost}, Description: #{coffee_with_milk_and_sugar.description}" # 输出 Cost: 2.7, Description: Coffee, with milk, with sugar

在上述代码中,Beverage 是抽象组件类,定义了 costdescription 抽象方法。Coffee 是具体组件类。MilkDecoratorSugarDecorator 是装饰器类,它们接受一个 Beverage 对象,并在其基础上添加新的功能(增加成本和修改描述)。通过层层装饰,可以为对象动态地添加不同的功能。

代理模式在 Ruby 中的应用

代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。

class RealImage
  def initialize(filename)
    @filename = filename
    load_image
  end

  def display
    puts "Displaying #{@filename}"
  end

  private

  def load_image
    puts "Loading #{@filename}"
  end
end

class ImageProxy
  def initialize(filename)
    @filename = filename
    @real_image = nil
  end

  def display
    @real_image ||= RealImage.new(@filename)
    @real_image.display
  end
end

# 使用代理模式
proxy = ImageProxy.new('image.jpg')
# 此时尚未真正加载图片
proxy.display # 输出 Loading image.jpg, Displaying image.jpg

在这段代码中,RealImage 类是实际的对象,它在初始化时会加载图片(这里通过 load_image 方法模拟加载过程)。ImageProxy 类是代理类,它持有一个 RealImage 对象的引用,但只有在调用 display 方法时才会真正创建 RealImage 对象。这样可以在需要时才加载实际对象,提高系统的性能和资源利用率。

模板方法模式在 Ruby 中的应用

模板方法模式是一种行为型设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

class AbstractClass
  def template_method
    step1
    step2
    step3
  end

  def step1
    puts "AbstractClass: Step 1 implementation"
  end

  def step2
    raise NotImplementedError, "Subclasses must implement #step2"
  end

  def step3
    puts "AbstractClass: Step 3 implementation"
  end
end

class ConcreteClass < AbstractClass
  def step2
    puts "ConcreteClass: Step 2 implementation"
  end
end

# 使用模板方法模式
concrete = ConcreteClass.new
concrete.template_method
# 输出 AbstractClass: Step 1 implementation
# 输出 ConcreteClass: Step 2 implementation
# 输出 AbstractClass: Step 3 implementation

在上述代码中,AbstractClass 定义了 template_method 方法,它包含了算法的骨架,由 step1step2step3 组成。其中 step1step3 有默认实现,而 step2 是抽象方法,需要子类实现。ConcreteClass 是子类,实现了 step2 方法。通过这种方式,子类可以在不改变算法整体结构的情况下,定制算法的特定步骤。

组合模式在 Ruby 中的应用

组合模式是一种结构型设计模式,它将对象组合成树形结构以表示“部分 - 整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

class Component
  def initialize(name)
    @name = name
  end

  def add(component)
    raise NotImplementedError, "Subclasses must implement #add"
  end

  def remove(component)
    raise NotImplementedError, "Subclasses must implement #remove"
  end

  def display
    raise NotImplementedError, "Subclasses must implement #display"
  end
end

class Leaf < Component
  def add(component)
    raise "Cannot add to a leaf"
  end

  def remove(component)
    raise "Cannot remove from a leaf"
  end

  def display
    puts "Leaf: #{@name}"
  end
end

class Composite < Component
  def initialize(name)
    super
    @children = []
  end

  def add(component)
    @children << component
  end

  def remove(component)
    @children.delete(component)
  end

  def display
    puts "Composite: #{@name}"
    @children.each do |child|
      child.display
    end
  end
end

# 使用组合模式
root = Composite.new('Root')
branch1 = Composite.new('Branch 1')
branch2 = Composite.new('Branch 2')
leaf1 = Leaf.new('Leaf 1')
leaf2 = Leaf.new('Leaf 2')

root.add(branch1)
root.add(branch2)
branch1.add(leaf1)
branch2.add(leaf2)

root.display
# 输出 Composite: Root
# 输出 Composite: Branch 1
# 输出 Leaf: Leaf 1
# 输出 Composite: Branch 2
# 输出 Leaf: Leaf 2

在这段代码中,Component 是抽象类,定义了添加、移除和显示的抽象方法。Leaf 类是叶子节点,它不能包含其他组件,因此 addremove 方法会抛出异常。Composite 类是组合节点,它可以包含其他组件,并实现了添加、移除和显示方法。通过组合模式,可以方便地构建和操作具有层次结构的对象。

桥接模式在 Ruby 中的应用

桥接模式是一种结构型设计模式,它将抽象部分与它的实现部分分离,使它们都可以独立地变化。

class Abstraction
  def initialize(implementation)
    @implementation = implementation
  end

  def operation
    @implementation.operation_implementation
  end
end

class RefinedAbstraction < Abstraction
  def operation
    "Refined " + super
  end
end

class Implementation
  def operation_implementation
    raise NotImplementedError, "Subclasses must implement #operation_implementation"
  end
end

class ConcreteImplementationA < Implementation
  def operation_implementation
    "ConcreteImplementationA"
  end
end

class ConcreteImplementationB < Implementation
  def operation_implementation
    "ConcreteImplementationB"
  end
end

# 使用桥接模式
implementation_a = ConcreteImplementationA.new
abstraction = Abstraction.new(implementation_a)
puts abstraction.operation # 输出 ConcreteImplementationA

implementation_b = ConcreteImplementationB.new
refined_abstraction = RefinedAbstraction.new(implementation_b)
puts refined_abstraction.operation # 输出 Refined ConcreteImplementationB

在上述代码中,Abstraction 类持有一个 Implementation 对象的引用,并通过 operation 方法调用 Implementationoperation_implementation 方法。RefinedAbstractionAbstraction 的子类,进一步扩展了 operation 方法。Implementation 是抽象实现类,定义了 operation_implementation 抽象方法。ConcreteImplementationAConcreteImplementationB 是具体实现类,实现了 operation_implementation 方法。通过桥接模式,抽象部分和实现部分可以独立变化,提高了代码的灵活性和可维护性。

解释器模式在 Ruby 中的应用

解释器模式是一种行为型设计模式,它给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

class Context
  def initialize
    @variables = {}
  end

  def set_variable(name, value)
    @variables[name] = value
  end

  def get_variable(name)
    @variables[name]
  end
end

class Expression
  def interpret(context)
    raise NotImplementedError, "Subclasses must implement #interpret"
  end
end

class VariableExpression < Expression
  def initialize(name)
    @name = name
  end

  def interpret(context)
    context.get_variable(@name)
  end
end

class AddExpression < Expression
  def initialize(left, right)
    @left = left
    @right = right
  end

  def interpret(context)
    @left.interpret(context) + @right.interpret(context)
  end
end

# 使用解释器模式
context = Context.new
context.set_variable('x', 5)
context.set_variable('y', 3)

x = VariableExpression.new('x')
y = VariableExpression.new('y')
add_expression = AddExpression.new(x, y)

puts add_expression.interpret(context) # 输出 8

在这段代码中,Context 类用于存储变量的值。Expression 是抽象表达式类,定义了 interpret 抽象方法。VariableExpression 表示变量表达式,它从 Context 中获取变量的值。AddExpression 表示加法表达式,它将左右两个表达式的值相加。通过这种方式,可以构建一个简单的表达式解释器,对特定语言的句子进行解释。

备忘录模式在 Ruby 中的应用

备忘录模式是一种行为型设计模式,它在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

class Originator
  def initialize(state)
    @state = state
  end

  def state
    @state
  end

  def state=(new_state)
    @state = new_state
  end

  def create_memento
    Memento.new(@state)
  end

  def restore_memento(memento)
    @state = memento.state
  end
end

class Memento
  def initialize(state)
    @state = state
  end

  def state
    @state
  end
end

class Caretaker
  def initialize(originator)
    @originator = originator
    @mementos = []
  end

  def save_state
    memento = @originator.create_memento
    @mementos << memento
  end

  def restore_state(index)
    memento = @mementos[index]
    @originator.restore_memento(memento)
  end
end

# 使用备忘录模式
originator = Originator.new('State 1')
caretaker = Caretaker.new(originator)

caretaker.save_state
originator.state = 'State 2'

caretaker.restore_state(0)
puts originator.state # 输出 State 1

在上述代码中,Originator 类是需要保存和恢复状态的对象,它提供了创建备忘录和从备忘录恢复状态的方法。Memento 类用于保存 Originator 的状态。Caretaker 类负责管理备忘录,包括保存状态和恢复状态。通过备忘录模式,可以在不破坏 Originator 封装性的情况下,实现对象状态的保存和恢复。

状态模式在 Ruby 中的应用

状态模式是一种行为型设计模式,它允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

class State
  def handle(context)
    raise NotImplementedError, "Subclasses must implement #handle"
  end
end

class ConcreteStateA < State
  def handle(context)
    puts "ConcreteStateA handles request"
    context.state = ConcreteStateB.new
  end
end

class ConcreteStateB < State
  def handle(context)
    puts "ConcreteStateB handles request"
    context.state = ConcreteStateA.new
  end
end

class Context
  def initialize
    @state = ConcreteStateA.new
  end

  def state=(new_state)
    @state = new_state
  end

  def request
    @state.handle(self)
  end
end

# 使用状态模式
context = Context.new
context.request # 输出 ConcreteStateA handles request
context.request # 输出 ConcreteStateB handles request

在这段代码中,State 是抽象状态类,定义了 handle 抽象方法。ConcreteStateAConcreteStateB 是具体状态类,实现了 handle 方法,在处理请求时会改变 Context 的状态。Context 类持有一个状态对象,并通过 request 方法调用当前状态的 handle 方法。通过状态模式,对象的行为可以根据其内部状态的变化而改变。

访问者模式在 Ruby 中的应用

访问者模式是一种行为型设计模式,它表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

class Element
  def accept(visitor)
    raise NotImplementedError, "Subclasses must implement #accept"
  end
end

class ConcreteElementA < Element
  def accept(visitor)
    visitor.visit_concrete_element_a(self)
  end

  def operation_a
    "Operation A of ConcreteElementA"
  end
end

class ConcreteElementB < Element
  def accept(visitor)
    visitor.visit_concrete_element_b(self)
  end

  def operation_b
    "Operation B of ConcreteElementB"
  end
end

class Visitor
  def visit_concrete_element_a(element)
    raise NotImplementedError, "Subclasses must implement #visit_concrete_element_a"
  end

  def visit_concrete_element_b(element)
    raise NotImplementedError, "Subclasses must implement #visit_concrete_element_b"
  end
end

class ConcreteVisitor < Visitor
  def visit_concrete_element_a(element)
    puts "ConcreteVisitor visiting #{element.operation_a}"
  end

  def visit_concrete_element_b(element)
    puts "ConcreteVisitor visiting #{element.operation_b}"
  end
end

# 使用访问者模式
element_a = ConcreteElementA.new
element_b = ConcreteElementB.new

visitor = ConcreteVisitor.new

element_a.accept(visitor) # 输出 ConcreteVisitor visiting Operation A of ConcreteElementA
element_b.accept(visitor) # 输出 ConcreteVisitor visiting Operation B of ConcreteElementB

在上述代码中,Element 是抽象元素类,定义了 accept 抽象方法。ConcreteElementAConcreteElementB 是具体元素类,实现了 accept 方法,用于接受访问者。Visitor 是抽象访问者类,定义了访问不同具体元素的抽象方法。ConcreteVisitor 是具体访问者类,实现了这些访问方法。通过访问者模式,可以在不改变元素类的情况下,为元素添加新的操作。