Ruby Design Patterns
Take your programming skills to the next level with interactive lessons and real-world projects.
Explore Coddy →Design patterns are reusable solutions to common problems in software design. They provide a structured approach to solving issues that frequently occur in software development. In Ruby, these patterns help developers create more maintainable, flexible, and efficient code.
Why Use Design Patterns in Ruby?
Design patterns offer several benefits:
- Improved code organization
- Enhanced maintainability
- Better scalability
- Faster development through proven solutions
- Easier collaboration among developers
Common Ruby Design Patterns
1. Singleton Pattern
The Singleton pattern ensures a class has only one instance and provides a global point of access to it. This is useful for managing shared resources or coordinating actions across a system.
require 'singleton'
class Logger
include Singleton
def log(message)
puts "#{Time.now}: #{message}"
end
end
# Usage
Logger.instance.log("This is a log message")
2. Factory Method Pattern
The Factory Method pattern defines an interface for creating an object but lets subclasses decide which class to instantiate. It promotes loose coupling between classes.
class Animal
def speak
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
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, "Invalid animal type: #{type}"
end
end
end
# Usage
dog = AnimalFactory.create_animal(:dog)
puts dog.speak # Output: Woof!
3. Observer Pattern
The Observer pattern defines a one-to-many dependency between objects. When one object changes state, all its dependents are notified and updated automatically.
module Subject
def initialize
@observers = []
end
def add_observer(observer)
@observers << observer
end
def delete_observer(observer)
@observers.delete(observer)
end
def notify_observers
@observers.each { |observer| observer.update(self) }
end
end
class NewsAgency
include Subject
attr_reader :news
def news=(news)
@news = news
notify_observers
end
end
class NewsChannel
def update(changed_subject)
puts "Breaking News: #{changed_subject.news}"
end
end
# Usage
agency = NewsAgency.new
channel1 = NewsChannel.new
channel2 = NewsChannel.new
agency.add_observer(channel1)
agency.add_observer(channel2)
agency.news = "Ruby 3.0 released!"
Best Practices for Using Design Patterns in Ruby
- Understand the problem before applying a pattern
- Don't force a pattern where it's not needed
- Combine patterns when appropriate
- Keep your implementations simple and readable
- Document your use of design patterns in your code
Design patterns are powerful tools in a Ruby developer's toolkit. They can significantly improve code quality and maintainability when used appropriately. As you continue to work with Ruby, you'll find opportunities to apply these patterns in your projects.
To further enhance your Ruby skills, consider exploring Ruby Metaprogramming and Ruby Refactoring Techniques. These concepts often work hand-in-hand with design patterns to create more flexible and efficient code.