Post

Structural Design Patterns: Adapter Method

Purpose

The Adapter Pattern is like a translator that helps two people who speak different languages understand each other. In software, it enables two systems with mismatched interfaces to work together without changing their internal logic. It “adapts” one system’s output to match the expectations of another system.

Explanation

Imagine you have a new electric car (let’s call it ElectricVehicle) that uses special controls to operate. However, your system(or app) is designed for traditional vehicles with a simpler interface, like “drive”. The electric car can’t directly plug into your app because its controls are too different.

Instead of redesigning either the car or your app, you create a bridge called an Adapter. This Adapter takes the electric car’s unique features and translates them into something your app understands. That way, you can “drive” the electric car using the same commands your app already supports.

Ruby Example: Adapting an Electric Car

Scenario

  • Your system works with all vehicles via a drive command.
  • An ElectricVehicle has its own unique methods like start_engine and accelerate.
  • To use the electric car with your system, you need an Adapter to convert “drive” into the right commands.

Step 1: Define the Generic Vehicle

1
2
3
4
5
6
# Expected interface for all vehicles
class GenericVehicle
  def drive
    raise NotImplementedError, "All vehicles must implement the 'drive' method."
  end
end

Step 2: Define the Electric Vehicle

1
2
3
4
5
6
7
8
9
10
# The new electric vehicle with its own methods
class ElectricVehicle
  def start_engine
    puts "Electric motor started."
  end

  def accelerate
    puts "Electric vehicle is now moving."
  end
end

Step 3: Define the Electric Vehicle Adapter

1
2
3
4
5
6
7
8
9
10
11
# The Adapter that bridges the gap
class ElectricVehicleAdapter < GenericVehicle
  def initialize(electric_vehicle)
    @electric_vehicle = electric_vehicle
  end

  def drive
    @electric_vehicle.start_engine
    @electric_vehicle.accelerate
  end
end

Put it all together

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# System that uses vehicles
class VehicleSystem
  def initialize(vehicle)
    @vehicle = vehicle
  end

  def start_trip
    puts "Getting ready to drive..."
    @vehicle.drive
  end
end

# Usage
electric_car = ElectricVehicle.new
adapter = ElectricVehicleAdapter.new(electric_car)

system = VehicleSystem.new(adapter)
system.start_trip

How it works?

  • GenericVehicle defines a simple drive method, which all vehicles must have.
  • ElectricVehicle doesn’t have drive but has its own methods (start_engine and accelerate).
  • ElectricVehicleAdapter acts as a middleman:
    • It wraps the ElectricVehicle instance.
    • When drive is called, it translates the command into start_engine and accelerate.
  • VehicleSystem doesn’t care whether the car is electric or not. It only knows how to call drive.

Why Use It?

  • Integration without modification: You can use existing or third-party systems without changing their code.
  • Flexibility: Easily adapt new systems or technologies into your existing workflow.

Cheers :)

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.