hubMediator
The Mediator design pattern is a behavioral pattern that defines an object that centralizes communication between various components, instead of allowing them to communicate directly.
A great example of a mediator may be the airport and how traffic is controlled there. The air traffic control tower acts as a mediator, ensuring that airplanes and runways communicate through it rather than directly with each other.
To build our example, we will need three classes. Airplane and Runway will be objects that want to communicate with each other, and ControlTower will be our mediator responsible for this communication.
class Airplane
attr_reader :code
def initialize(code:)
@code = code
end
end
class Runway
attr_reader :code, :status
def initialize(code:, status: 'Available')
@code = code
@status = status
end
end
class ControlTower
attr_reader :code, :airplanes, :runways
def initialize(code:)
@code = code
@airplanes = []
@runways = []
end
def add_airplane(airplane)
@airplanes << airplane
end
def add_runway(runway)
@runways << runway
end
end
To use the Mediator pattern, we will have to add the tower attribute to both the Airplane and Runway classes. This attribute will be assigned when you add these objects to the ControlTower object.
class Airplane
attr_reader :code
attr_accessor :tower
# ...
end
class Runway
attr_reader :code, :status
attr_accessor :tower
# ...
end
class ControlTower
# ...
def add_airplane(airplane)
@airplanes << airplane
airplane.tower = self
end
def add_runway(runway)
@runways << runway
runway.tower = self
end
end
At this point we can start adding our communication methods. The first one will be request_take_off, this request will be sent from the Airplane to the ControlTower.
class Airplane
# ...
def request_takeoff
tower.request_takeoff(self)
end
end
After the ControlTower receives this request, it will display a log that such a request has been sent, then it will find an available Runway(or throw an error that there is none), and finally it will send a notification to the Runway.
class ControlTower
# ...
def request_takeoff(airplane)
puts("#{airplane.code} send takeoff request!")
notify_available_runway
end
def notify_available_runway
available_runway.prepare_for_takeoff
end
private
def available_runway
runways.find do|runway|
runway.status == 'Available'
end || raise('There are no available runways!')
end
end
After receiving the information, the Runway will have to change its status to Busy.
class Runway
# ...
def prepare_for_takeoff
@status = 'Busy'
end
end
Now we can use our code in action.
# Create airplanes
tupolev = Airplane.new(code: 'T154')
boeing = Airplane.new(code: 'B738')
airbus = Airplane.new(code: 'A318')
# Create runways
runway_a = Runway.new(code: 'RUNWAY_A')
runway_b = Runway.new(code: 'RUNWAY_B')
# Create tower
tower = ControlTower.new(code: 'TOWER_A')
# Add airplanes to tower
tower.add_airplane(tupolev)
tower.add_airplane(boeing)
tower.add_airplane(airbus)
# Add runways to tower
tower.add_runway(runway_a)
tower.add_runway(runway_b)
# Request takeoffs
tupolev.request_takeoff # => T154 send takeoff request!run
runway_a.status # => Busy
boeing.request_takeoff
runway_b.status # => Busy
# Raise an error when there are no available runways
airbus.request_takeoff # => RuntimeError: There are no available runways!
A pattern prepared in this way allows you to create a central place where communication between objects takes place. If you want to practice, you can add new features to my example, such as:
checking weather conditions on the runway before takeoff
adding communication between different towers
adding the runway departure function