I. Strategy Pattern

The Strategy pattern is a behavioral design pattern that enables an algorithm’s behavior to be selected at runtime. It defines a family of algorithms, encapsulates each algorithm, and makes the algorithms interchangeable within that family. In this way, the Strategy pattern allows the algorithm to vary independently of the clients that use it.

Here’s an example of the Strategy pattern in Ruby:

class Context
  attr_writer :strategy

  def initialize(strategy)
    @strategy = strategy
  end

  def execute_strategy
    @strategy.execute
  end
end

class ConcreteStrategyA
  def execute
    puts 'Executing strategy A'
  end
end

class ConcreteStrategyB
  def execute
    puts 'Executing strategy B'
  end
end

context = Context.new(ConcreteStrategyA.new)
context.execute_strategy

context.strategy = ConcreteStrategyB.new
context.execute_strategy

In this example, the Context class is responsible for executing the selected strategy. The ConcreteStrategyA and ConcreteStrategyB classes represent different strategies that can be used by the Context class. By changing the strategy at runtime, the Context class can execute different algorithms without changing its code.

II. Decorator Pattern

The Decorator pattern is a structural design pattern that allows behavior to be added to individual objects dynamically. It is useful for extending the functionality of objects without modifying their structure. The Decorator pattern involves creating a set of decorator classes that are used to wrap concrete components.

Here’s an example of the Decorator pattern in Ruby:

class Component
  def operation
    'Component operation'
  end
end

class ConcreteComponent < Component
  def operation
    'Concrete component operation'
  end
end

class Decorator < Component
  attr_reader :component

  def initialize(component)
    @component = component
  end

  def operation
    @component.operation
  end
end

class ConcreteDecoratorA < Decorator
  def operation
    "Decorator A [#{super}]"
  end
end

class ConcreteDecoratorB < Decorator
  def operation
    "Decorator B [#{super}]"
  end
end

component = ConcreteComponent.new

decorator_a = ConcreteDecoratorA.new(component)
decorator_b = ConcreteDecoratorB.new(decorator_a)

puts decorator_b.operation

III. Template Method Pattern

The Template Method pattern is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure. It is useful for implementing algorithms that follow a common sequence of steps but allow variations in certain steps.

Here’s an example of the Template Method pattern in Ruby:

class AbstractClass
  def template_method
    base_operation1
    required_operation1
    base_operation2
    hook
  end

  def base_operation1
    puts 'Abstract class: base operation 1'
  end

  def base_operation2
    puts 'Abstract class: base operation 2'
  end

  def required_operation1
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  def hook
  end
end

class ConcreteClassA < AbstractClass
  def required_operation1
    puts 'Concrete class A: required operation 1'
  end

  def hook
    puts 'Concrete class A: hook'
  end
end

class ConcreteClassB < AbstractClass
  def required_operation1
    puts 'Concrete class B: required operation 1'
  end
end

ConcreteClassA.new.template_method
ConcreteClassB.new.template_method

In this example, the AbstractClass defines the template method that consists of a sequence of steps. The ConcreteClassA and ConcreteClassB subclasses implement the required operations and hooks to customize the algorithm’s behavior.

IV. Command Pattern

The Command pattern is a behavioral design pattern that encapsulates a request as an object, thereby allowing parameterization of clients with different requests, queuing of requests, and logging of requests. It decouples the sender of a request from the receiver, providing a way to issue requests without knowing anything about the request or how it will be handled.

Here’s an example of the Command pattern in Ruby:

class Command
  def execute
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

class ConcreteCommandA < Command
  def execute
    puts 'Executing command A'
  end
end

class ConcreteCommandB < Command
  def execute
    puts 'Executing command B'
  end
end

class Invoker
  attr_writer :command

  def execute_command
    @command.execute
  end
end

invoker = Invoker.new

invoker.command = ConcreteCommandA.new
invoker.execute_command

invoker.command = ConcreteCommandB.new
invoker.execute_command

In this example, the Command class defines the interface for executing commands. The ConcreteCommandA and ConcreteCommandB classes encapsulate specific commands as objects. The Invoker class is responsible for executing the commands without knowing their specific implementations.

V. Adapter Pattern

The Adapter pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces, converting the interface of a class into another interface that a client expects. The Adapter pattern is useful when integrating new components into an existing system without modifying the existing code.

Here’s an example of the Adapter pattern in Ruby:

class Target
  def request
    'Target: The default target\'s behavior.'
  end
end

class Adaptee
  def specific_request
    '.eetpadA eht fo roivaheb laicepS'
  end
end

class Adapter < Target
  def initialize(adaptee)
    @adaptee = adaptee
  end

  def request
    "Adapter: (TRANSLATED) #{@adaptee.specific_request.reverse}"
  end
end

target = Target.new
puts target.request

adaptee = Adaptee.new
adapter = Adapter.new(adaptee)
puts adapter.request

In this example, the Target class defines the interface that the client expects. The Adaptee class has an incompatible interface that needs to be adapted. The Adapter class acts as a bridge between the Target and Adaptee, allowing them to work together seamlessly.