GameCharacter Interface Listing
Public Interface GameCharacter
Sub Eat()
Sub Talk()
Sub Fight()
Sub Move()
End Interface
Soldier Class Listing
Public Class Soldier
Implements GameCharacter
Public Sub Eat() Implements GameCharacter.Eat
Console.WriteLine("Soldier is eating")
End Sub
Public Sub Fight() Implements GameCharacter.Fight
Console.WriteLine("Soldier is fighting")
End Sub
Public Sub Move() Implements GameCharacter.Move
Console.WriteLine("Soldier is moving slowly")
End Sub
Public Sub Talk() Implements GameCharacter.Talk
Console.WriteLine("Soldier is talking")
End Sub
End Class
Let us assume that the Animal class and the inheriting sub-classes for specific animals were created by another developer on the team.
Animal Class Listing
Public MustInherit Class Animal
Public Sub Sleep()
Console.WriteLine("Animal is sleeping")
End Sub
Public Sub Drink()
Console.WriteLine("Animal is drinking")
End Sub
Public Sub Eat()
Console.WriteLine("Animal is eating")
End Sub
Public Sub Graze()
Console.WriteLine("Animal is grazing")
End Sub
Public Sub MakeSound()
Console.WriteLine("Animal is making some noise")
End Sub
End Class
The TrainedElephant class extends the Animal class by adding the Move and Attack methods
TrainedElephant Class Listing
Public Class TrainedElephant
Inherits Animal
Public Sub Move()
Console.WriteLine("TrainedElephant is moving")
End Sub
Public Sub Attack()
Console.WriteLine("TrainedElephant is attack")
End Sub
End Class
Let us have a quick look at our class and interface hierarchy
And finally, lets list our requirement. With an existing design that resembles this, we would like to maintain a list of all character instances in the game including humans as well as animals that can fight and move. A quick solution is to use a generic list that holds GameCharacter objects. Since Soldiers natively implement the GameCharacter interface, it is quite easy to add a Soldier to this list. However, there is no relation between the Animal class and the GameCharacter interface and neither does the TrainedElephant class implement the Animal interface. It, therefore makes it impossible to add the TrainedElephant as a GameCharacter to the list.
One solution is to modify the code for the TrainedElephant class so that it implements the GameCharacter Interface. Although this seems easy from the looks of it, this may not be practical in a real life application where this portion of the code is built by another developer or when the source code for this class is not available for modification. In such scenarios, we can employ the services of the Adapter pattern to adapt the functionality of the TrainedElephant class to map to the GameCharacter class.
The TrainedElephantAdapter class simply wraps around a TrainedElephant object while implementing the GameCharacter interface. Thus, we do not need to modify the source code for the TrainedElephant or the Animal class and can use this TrainedElephantAdapter object interchangeably as a GameCharacter.
TrainedElephantAdapter Class Listing
Public Class TrainedElephantAdapter
Implements GameCharacter
Private _oElephant As TrainedElephant
Public Sub New(ByVal oElephant As TrainedElephant)
_oElephant = oElephant
End Sub
Public Sub Eat() Implements GameCharacter.Eat
_oElephant.Eat()
End Sub
Public Sub Fight() Implements GameCharacter.Fight
_oElephant.Attack()
End Sub
Public Sub Move() Implements GameCharacter.Move
_oElephant.Move()
End Sub
Public Sub Talk() Implements GameCharacter.Talk
_oElephant.MakeSound()
End Sub
End Class
Our class diagram now contains our new TrainedElephantAdapter which encapsulates the TrainedElephant object while implementing the GameCharacter interface
Finally, a little test harness using the TrainedElephantAdapter to do the magic for us
modMain Module Listing
Module modMain
Sub Main()
Dim GameCharacters As List(Of GameCharacter) = New List(Of GameCharacter)
GameCharacters.Add(New Soldier)
'And here is the Wrapped up TrainedElephant
GameCharacters.Add(New TrainedElephantAdapter(New TrainedElephant))
For Each oGC As GameCharacter In GameCharacters
oGC.Eat() : oGC.Fight() : oGC.Move() : oGC.Talk()
Next
Console.ReadLine()
End Sub
End Module
And the results of using the Adapter pattern
No comments:
Post a Comment