Deep Dive into Behavioral Patterns - The Mediator Pattern.

Hey software designers! Today, we’re diving into the Mediator pattern. This pattern is essential for reducing the complexity of communication between multiple objects or classes. Let’s explore its workings, benefits, and real-world applications with detailed examples.

What is the Mediator Pattern?

The Mediator pattern is a behavioral design pattern that defines an object that encapsulates how a set of objects interact. This pattern promotes loose coupling by keeping objects from referring to each other explicitly and allows their interaction to be varied independently.

Real-World Scenario

Imagine you’re developing a chat application where users can send messages to each other. Each user can send and receive messages without knowing the details of how the messages are delivered.

The Problem

When multiple objects need to communicate with each other, direct communication can lead to a tightly coupled and hard-to-maintain system. Adding or modifying communication paths can be difficult without changing existing code.

Without Mediator Pattern

class User
  attr_reader :name

  def initialize(name)
    @name = name
    @contacts = []
  end

  def add_contact(contact)
    @contacts << contact
  end

  def send_message(message, recipient)
    recipient.receive_message(message, self)
  end

  def receive_message(message, sender)
    puts "#{sender.name} to #{name}: #{message}"
  end
end

alice = User.new('Alice')
bob = User.new('Bob')

alice.add_contact(bob)
bob.add_contact(alice)

alice.send_message('Hello, Bob!', bob)

Drawbacks: The code is tightly coupled and difficult to extend to support new communication paths.

The Solution: Mediator Pattern

Using the Mediator pattern, we can centralize the communication logic, making the system easier to maintain and extend.

With Mediator Pattern

Step 1: Define the Mediator Interface

class ChatMediator
  def send_message(message, sender, recipient)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

Step 2: Create Concrete Mediator

class ConcreteChatMediator < ChatMediator
  def send_message(message, sender, recipient)
    recipient.receive_message(message, sender)
  end
end

Step 3: Modify the Colleagues to Use the Mediator

class User
  attr_reader :name

  def initialize(name, mediator)
    @name = name
    @mediator = mediator
  end

  def send_message(message, recipient)
    @mediator.send_message(message, self, recipient)
  end

  def receive_message(message, sender)
    puts "#{sender.name} to #{name}: #{message}"
  end
end

mediator = ConcreteChatMediator.new
alice = User.new('Alice', mediator)
bob = User.new('Bob', mediator)

alice.send_message('Hello, Bob!', bob)

Benefits: Centralizes the communication logic, promoting loose coupling and making the system easier to maintain and extend.

Real-World Benefits

Scenario: Adding New Communication Features

Imagine you need to add new communication features (e.g., group messages). Using the Mediator pattern, you can easily extend the communication logic without modifying the existing code.

Without Mediator Pattern:

class User
  def send_group_message(message, recipients)
    recipients.each { |recipient| send_message(message, recipient) }
  end
end

alice.send_group_message('Hello, everyone!', [bob, charlie])

Drawbacks: Tightly coupled code that is difficult to maintain and extend.

With Mediator Pattern:

class ConcreteChatMediator < ChatMediator
  def send_group_message(message, sender, recipients)
    recipients.each { |recipient| send_message(message, sender, recipient) }
  end
end

mediator.send_group_message('Hello, everyone!', alice, [bob, charlie])

Benefits: Clean, maintainable code with high flexibility and extensibility.

Conclusion

The Mediator pattern is a powerful tool for reducing the complexity of communication between multiple objects or classes. It promotes loose coupling, scalability, and maintainability in your code. By using the Mediator pattern, you can easily manage and extend the communication logic in your system without tightly coupling the code. Incorporate the Mediator pattern into your design strategies to build more robust and adaptable software systems.

Stay tuned for more insights into software design principles and patterns.

Thôi Lo Code Đi Kẻo Sếp nạt!!