Design patterns – Part 11: Bridge pattern
In part 11 of Design pattern series we will go into creating and using the Bridge design pattern. It is moderately used and uses encapsulation, inheritance and aggregation to separate responsibilities into other classes.
The Bridge pattern decouples an abstraction from its implementation so that the two can vary independently.
Usage
The pattern is most useful, when both classes (implementation and abstraction) are assigned to different task handling. In our example, we will look at how to separate data and actions to build a list of products and navigate it.
Data representation class
This is an abstract class with only navigational methods specified. Data representation class must implement navigational logic in its methods and thus assures that no other class will change or handle any properties without data representation class knowledge.
Also, for needs of our example, we will also define a type that will contain product id, name and price.
Type TBridgeData strId As String strName As String dPrice As Double End Type Class CBridgeDataObject Sub NextRecord () End Sub Sub PrevRecord () End Sub Sub AddRecord (strId As String, strName As String,_ dPrice As Double) End Sub Sub RemoveRecord (strId As String ) End Sub Sub ShowRecord () End Sub Function ShowAllRecords () As String End Function End Class
Product data class
Class itself inherits from Data representation abstract class. Also, it contains all navigational logic as well as data handling.
Beware that for this example, I did not actually load the data from the database. Instead I created five (5) products in the class construct. In real life, you should have read the data from your database!
Class CBridgeProductData As CBridgeDataObject
Private m_nCurrent As Integer
Private m_AProducts () As TBridgeData
Sub New ()
m_ncurrent = 0
Redim m_AProducts(4)
m_AProducts(0).strId = "PR-0001"
m_AProducts(0).strName = "Product 1"
m_AProducts(0).dPrice = 100.00
m_AProducts(1).strId = "PR-0002"
m_AProducts(1).strName = "Product 2"
m_AProducts(1).dPrice = 1000.00
m_AProducts(2).strId = "PR-0003"
m_AProducts(2).strName = "Product 3"
m_AProducts(2).dPrice = 150.00
m_AProducts(3).strId = "PR-0004"
m_AProducts(3).strName = "Product 4"
m_AProducts(3).dPrice = 400.00
m_AProducts(4).strId = "PR-0005"
m_AProducts(4).strName = "Product 5"
m_AProducts(4).dPrice = 330.00
End Sub
Sub NextRecord ()
If (m_nCurrent < Ubound (m_AProducts)) Then
m_nCurrent = m_nCurrent + 1
End If
End Sub
Sub PrevRecord ()
If (m_nCurrent > 0) Then
m_nCurrent = m_nCurrent - 1
End If
End Sub
Sub AddRecord (strId As String, strName As String,_
dPrice As Double)
Dim n As Integer
n = Ubound (m_AProducts) + 1
Redim Preserve m_AProducts (n)
m_AProducts(n).strId = strId
m_AProducts(n).strName = strName
m_AProducts(n).dPrice = dPrice
End Sub
Sub RemoveRecord (strId As String)
Dim n As Integer
Dim m As Integer
Dim nCount As Integer
Dim nIndex As Integer
m = 0
nIndex = -1
nCount = Ubound (m_AProducts)
For n = 0 To nCount
If (m_AProducts (n).strId <> strId) Then
m_AProducts (m).strId = m_AProducts (n).strId
m_AProducts (m).strName = m_AProducts (n).strName
m_AProducts (m).dPrice = m_AProducts (n).dPrice
m = m + 1
Else
nIndex = n
End If
Next
Redim Preserve m_AProducts (nCount - 1)
If (m_nCurrent > n) Then Call Me.PrevRecord ()
End Sub
Sub ShowRecord ()
Dim strDisplay As String
strDisplay = m_AProducts (m_nCurrent).strId & { } &_
m_AProducts (m_nCurrent).strName & { €} &_
m_AProducts (m_nCurrent).dPrice
Messagebox strDisplay
End Sub
Function ShowAllRecords() As String
Dim n As Integer
Dim strDisplay As String
strDisplay = ""
For n = 0 To Ubound (m_AProducts)
strDisplay = strDisplay & Chr(13) &_
m_AProducts (n).strId & { } &_
m_AProducts (n).strName & { €} &_
m_AProducts (n).dPrice
Next
ShowAllRecords = strDisplay
End Function
End Class
Product base class
Now, that we have our data classes created, we need to build an abstraction class that will call actual navigation and display the list contents or item if necessary. As we might have multiple classes that should have same functionality, it is a must to create a base class first. This class will encapsulate Data representation abstract class.
Class CBridgeProductBase
Private m_DataObj As CBridgeDataObject
Private m_strGroup As String
Public Property Get Data
Set Data = m_DataObj
End Property
Public Property Set Data
Set m_DataObj = Data
End Property
Sub New (strGroup As String)
m_strGroup = strGroup
End Sub
Sub Next ()
Call m_DataObj.NextRecord ()
End Sub
Sub Prev ()
Call m_DataObj.PrevRecord ()
End Sub
Sub Add (strId As String, strName As String, dPrice As Double)
Call m_DataObj.AddRecord (strId, strName, dPrice)
End Sub
Sub Remove (strId As String)
Call m_DataObj.RemoveRecord (strId)
End Sub
Sub Show ()
Call m_DataObj.ShowRecord()
End Sub
Sub ShowAll ()
Messagebox "Product group: " & m_strGroup & Chr (13) &_
m_DataObj.ShowAllRecords()
End Sub
End Class
Concrete product class
Concrete product class in our case, will only be used to alter presentation when ShowAll method is called. This is not a must.
Class CBridgeProducts As CBridgeProductBase
Sub New (strGroup As String)
End Sub
Sub ShowAll ()
Messagebox "Displaying all products"
Call CBridgeProductBase..ShowAll ()
End Sub
End Class
Implementation
For test purposes, I have created an agent that will:
- create product list
- navigate forward and backward
- add an item to the list
- remove an item from the list
- display single product or all products at any time,
Sub Initialize
Dim products As CBridgeProducts
Dim data As CBridgeProductData
Set products = New CBridgeProducts ("product group 1")
Set products.Data = New CBridgeProductData ()
Call products.Show ()
Call products.Next ()
Call products.Show ()
Call products.Prev ()
Call products.Show ()
Call products.ShowAll ()
Call products.Add ("PR-0010", "New product", 1475.00)
Call products.ShowAll ()
Call products.Remove ("PR-0004")
Call products.ShowAll ()
End Sub
Leave a Reply