The Bridge Design Pattern is a structural pattern that separates abstraction from implementation so that the two can vary independently. It involves creating a bridge interface that decouples an abstraction from its implementation. This pattern is useful when you want to avoid a permanent binding between an abstraction and its implementation.

Let's illustrate the Bridge Pattern with a Ruby on Rails example. In this example, we'll create a bridge between different notification types and the way they are sent.

Abstraction: Notification

# Abstraction: Notification
class Notification
  def initialize(sender)
    @sender = sender
  end

  def send_message
    raise NotImplementedError, 'Subclasses must implement the send_message method'
  end
end

Refined Abstraction: EmailNotification, SMSNotification

# Refined Abstraction: EmailNotification
class EmailNotification < Notification
  def send_message
    @sender.send_message('Sending email notification.')
  end
end

# Refined Abstraction: SMSNotification
class SMSNotification < Notification
  def send_message
    @sender.send_message('Sending SMS notification.')
  end
end

Implementor: MessageSender

# Implementor: MessageSender
class MessageSender
  def send_message(message)
    raise NotImplementedError, 'Subclasses must implement the send_message method'
  end
end

Concrete Implementor: EmailSender, SMSSender

# Concrete Implementor: EmailSender
class EmailSender < MessageSender
  def send_message(message)
    puts "EmailSender: #{message}"
  end
end

# Concrete Implementor: SMSSender
class SMSSender < MessageSender
  def send_message(message)
    puts "SMSSender: #{message}"
  end
end

Client Code: Using the Bridge

# Client code using the Bridge Pattern
email_sender = EmailSender.new
sms_sender = SMSSender.new

email_notification = EmailNotification.new(email_sender)
sms_notification = SMSNotification.new(sms_sender)

email_notification.send_message
sms_notification.send_message

In this example:

  • Notification is the abstraction, representing different types of notifications.
  • EmailNotification and SMSNotification are refined abstractions, representing specific types of notifications.
  • MessageSender is the implementor interface, defining the method for sending messages.
  • EmailSender and SMSSender are concrete implementors, providing specific implementations for sending email and SMS messages.
  • The client code uses the Bridge Pattern to associate different types of notifications with different message senders, allowing the two to vary independently.

The Bridge Pattern is useful when you want to avoid a permanent binding between an abstraction and its implementation. It allows you to extend both hierarchies independently and change their implementations dynamically at runtime.