Pattern Tweaking
While I agree with the GoF that the Bridge is a very useful
pattern and definitely deserves a place among the patterns, I am not sure I
like their internal arrangement of the pattern.
First of all, I think the name is not the best one to
describe the pattern. I prefer to call it the Drill or Draw-Bridge pattern. You
see, in line with the intent and operation of the pattern, Abstraction-classes
should be in their own COG. Implementation classes should also be in their own
COG.
In a drill we have several speed settings along with
reversible rotation of the motor. This in effect gives us interchangeable
motor behaviours. In the case of the drill-bits, we can swap them and use
concrete-bits or metal-bits. We can also change the bit-size. So we have extensibility
and adaptability in two dimensions: motor operation and drill-bit behavior.
Based on the discussion above, we could have similarly named
the pattern accelerator/gear-stick since we vary engine speed with gas and vary
the drive-ratio with the gear-stick.
As implemented in GoF, the master class is the Abstraction
class which aggregates Implementations. To me, this feels a bit like having a
bet with someone and letting them hold both bets. To overcome this shortfall,
I would also introduce a new master class called the shell or container class
which holds on to both the abstraction and implementation classes. In this way
they are both relegated to being helper-classes as the pattern intended. I
would also include two more classes within the shell class. These would be a
switch class and a signal class. Work would then be accomplished by configuring
the shell-class with an abstraction class (CD-player/turn-table or
motor-speed-fast/motor-speed-slow) and implementation class (speaker/headphone
or concrete-bit/metal-bit). You also need to set the switch-class within the
shell class to a position (volume-high/volume-low or
forward-rotation/reverse-rotation). The Bridge-shell class would then instruct
the Abstraction class to set the signal properties of the signal class. The
Implementation class would then sample the signal class and translate the
signal into work.
The code below is a bit rough-hewn and would certainly be
subject to a lot of refinement, but off the top of my head it might look
something like the following.
Class Abstraction_Motor
Private Function Abstract()
Private MotorSpeed As Integer
'Represents the signal Class which is the intermediary between
' the abstraction and implementation.
Private Gear
To make this work really nicely, we could probably implement
the whole thing with events where the Abstraction-class raises an event when it
performs an action or changes its state. This would then trigger an updating
of state in the signal class (which temporarily stores outputs of the
abstraction-class or the results of its work). Change in the signal class
could then trigger a change in the event-listeners which would be the
implementation class. This would take the state of the signal class and do some
useful work in its implementation method.
Listing 5
Function Spin(ByVal Implementation As Drill_Bit)
' Make the Drill bit spin fast
End Function
End Class
Class Implementation_ DrillBit
Private Function Implement()
End Class
Class Bridge_Drill
Dim Inner_Motor As Abstract_Motor
Dim Projecting_DrillBit As Implementation_DrillBit
Dim m_speedSetting As Integer
Public Property SpeedSetting() 'Can be set independently
Set(ByVal Value)
InnerMotor.MotorSpeed = value
End Set
End Property
Public Property DrillBit()
Drillbit = value
End set
End Property
Public Property InnerMotor()
InnerMotor = value
End set
End Property
Function DoWork_MakeHole()
Inner_Motor.Spin(Projecting_DrillBit)
End Function
End Class
Dim Motor As New Abstraction_Motor
Dim DrillBit As New Implementation_DrillBit
' Client Code to make the bridge do some useful work.
Dim Drill As New Bridge_Drill(Motor, DrillBit)
Drill.DoWork_MakeHole