The Adapter Design Pattern is a structural pattern that allows incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces by converting the interface of a class into another interface that a client expects. This pattern is particularly useful when integrating new components or systems that have different interfaces.
Let's consider an example in a Ruby on Rails context where we have an existing class that fetches user data and a new system that expects data in a different format. We'll create an adapter to make these two systems work seamlessly.
Existing System: Fetching User Data
# Existing system with a different interface
class LegacyUserFetcher
def fetch_user_info
# Simulating fetching user data from the legacy system
{ name: 'John Doe', email: '[email protected]' }
end
end
New System: Expects Data in a Different Format
# New system expecting user data in a different format
class NewUserSystem
def display_user(name:, email:)
# Simulating displaying user data in the new system
puts "User: #{name}, Email: #{email}"
end
end
Adapter: Adapting the Existing System to the New System
# Adapter to make the existing system compatible with the new system
class UserAdapter
def initialize(legacy_user_fetcher)
@legacy_user_fetcher = legacy_user_fetcher
end
def adapt_and_display_user
user_info = @legacy_user_fetcher.fetch_user_info
display_user_in_new_system(user_info)
end
private
def display_user_in_new_system(user_info)
# Adapting the user data to the format expected by the new system
name = user_info[:name]
email = user_info[:email]
# Using the new system to display the user
new_system = NewUserSystem.new
new_system.display_user(name: name, email: email)
end
end
Client Code: Using the Adapter
# Client code using the adapter pattern
legacy_user_fetcher = LegacyUserFetcher.new
adapter = UserAdapter.new(legacy_user_fetcher)
# Using the adapter to fetch and display user data in the new system
adapter.adapt_and_display_user
In this example:
-
LegacyUserFetcher
represents the existing system with a different interface. -
NewUserSystem
represents the new system expecting user data in a different format. -
UserAdapter
is the adapter that bridges the gap between the existing system and the new system. It takes the user data fetched from the existing system, adapts it to the format expected by the new system, and then uses the new system to display the user.
The key components of the Adapter Pattern are:
-
Target (
NewUserSystem
): The interface that the client expects. -
Adaptee (
LegacyUserFetcher
): The class with an incompatible interface that needs to be adapted. -
Adapter (
UserAdapter
): The class that implements the target interface and uses an instance of the adaptee to achieve compatibility.
The Adapter Pattern is especially useful when integrating legacy systems with new systems or when dealing with third-party libraries with different interfaces. It allows for a smooth transition and integration without modifying the existing codebase extensively.