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.
Public comments are closed, but I love hearing from readers. Feel free to contact me with your thoughts.