Implementing the Strategy Pattern in Ruby

Introduction to the Strategy Pattern in Ruby

Welcome back! We are continuing our exploration through Behavioral Patterns with Ruby. Previously, we delved into command-like behavior using Procs and Blocks and examined the Observer pattern. Now, we'll investigate the Strategy Pattern using Ruby's unique object-oriented features and dynamic capabilities.

What You'll Learn

In this lesson, you'll learn how to implement the Strategy Pattern using Ruby's object-oriented design. We'll simplify the pattern into digestible parts and demonstrate its practical application through a clear example.

Imagine a scenario where you have a ShoppingCart class, capable of handling payments through different methods like credit cards or PayPal. By employing the Strategy Pattern, we can encapsulate these payment strategies in separate classes and easily switch between them within the ShoppingCart class.

Strategy and Concrete Strategies Code Explanation

Ruby leverages its dynamic capabilities to implement the Strategy Pattern using classes without explicit interfaces. We'll start by defining a PaymentStrategy module providing a common payment method, and subsequently create concrete strategies such as CreditCardStrategy and PayPalStrategy that include this module and provide specific behavior:

# This module serves as a blueprint for payment strategies, 
# requiring the definition of the `pay` method.
module PaymentStrategy
  def pay(amount)
    # Raises an error if the `pay` method is not implemented by a strategy class.
    raise NotImplementedError, 'Payment method not implemented'
  end
end

# A strategy class that implements payment via Credit Card.
class CreditCardStrategy
  include PaymentStrategy

  def initialize(card_number)
    @card_number = card_number # Stores the credit card number.
  end

  # Implements the payment logic specific to credit card payment.
  def pay(amount)
    puts "Paid #{amount} using Credit Card: #{@card_number}"
  end
end

# A strategy class that implements payment via PayPal.
class PayPalStrategy
  include PaymentStrategy

  def initialize(email)
    @user_email = email # Stores the user's PayPal email.
  end

  # Implements the payment logic specific to PayPal payment.
  def pay(amount)
    puts "Paid #{amount} using PayPal: #{@user_email}"
  end
end

In these classes, Ruby's modules are used for shared behavior, while individual classes provide their own specific payment logic. The pay method is a shared interface implemented by the concrete strategy classes.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal