你考虑过在你的设计中使用接口吗?我想他们会帮上大忙的。我
asked a question
使用接口,您可以避免思考“我需要什么样的数据容器来执行此操作?”而是思考“我需要什么样的操作?”下面是一个简单的示例,说明如何对代码进行建模,以便在战斗中提取攻击方法:
Public Interface IAttacker
Function GetAttackDamage() As Double
Property Name As String
End Interface
Public Class Character
Implements IAttacker
Public Property Name As String Implements IAttacker.Name
Public Property Weapons As List(Of IWeapon)
Public Property SpecialTeamAttackMove As IWeapon
Public Function GetAttackDamage() As Double _
Implements IAttacker.GetAttackDamage()
'Get the sum of the damage in the weapons list'
Return Weapons.Select(Function(iw) iw.Damage).Sum()
End Function
End Class
Public Class Team
Implements IAttacker
Public Property Characters As List(Of Character) = _
New List(Of Character)()
Public Property Name As String Implements IAttacker.Name
Public Function GetAttackDamage() As Double _
Implements IAttacker.GetAttackDamage()
'Get the sum of the damage of the SpecialTeamAttackMove'
'of each character on the team'
Return Characters.Select(Function(c) _
c.SpecialTeamAttackMove.Damage).Sum())
End Function
End Public
Public Class Battle
Public Property AttackerA As IAttacker
Public Property AttackerB As IAttacker
Public Sub New(attackerA As IAttacker, attackerB As IAttacker)
Me.AttackerA = attackerA
Me.AttackerB = attackerB
End Sub
'This function returns the "winner" of the fight, unless it is a tie'
Public Function Fight() As IAttacker
If Me.AttackerA.GetAttackDamage() = Me.AttackerB.GetAttackDamage() Then
Return Nothing
ElseIf Me.AttackerA.GetAttackDamage() > _
Me.AttackerB.GetAttackDamage() Then
Return Me.AttackerA
Else
Return Me.AttackerB
End If
End Function
End Class
在上述代码中
Battle
类只知道它需要一个实现
IAttacker
. 它不关心对象如何实现
GetAttackDamage()
,只是它可以在需要时调用方法。这个
Name
属性也被抽象到接口中。请参阅以下有关如何工作的程序示例:
Public Sub BattleBetweenTwoCharacters()
'In this example, two characters are instantiated. Assume the "..." is where'
'you add weapons and other properties. The characters fight and the winning'
'IAttacker is returned'
Dim charA As Character = New Character() With {...}
Dim charB As Character = New Character() With {...}
Dim winningChar As IAttacker = New Battle(charA, charB).Fight()
If winningChar Is Nothing Then
Console.WriteLine("It was a tie.")
Else
Console.WriteLine("{0} was the winner",winningChar.Name)
End If
End Sub
Public Sub BattleBetweenTwoCharacters()
'In this example, several characters and a team are instantiated. '
'Assume the "..." is where you add weapons and other properties. A '
'fight takes place and the winner is returned.'
Dim charA As Character = New Character() With {...}
Dim charB As Character = New Character() With {...}
Dim charC As Character = New Character() With {...}
Dim teamAB As New Team()
teamAB.Characters.Add(charA)
teamAB.Characters.Add(charB)
'Here, a team fights a character. The Battle.Fight method will call '
'GetAttackDamage() on each object, even though a team implements'
'it differently than a single character.'
Dim winner As IAttacker = New Battle(teamAB, charB).Fight()
If winningChar Is Nothing Then
Console.WriteLine("It was a tie.")
Else
Console.WriteLine("{0} was the winner",winningChar.Name)
End If
End Sub
希望您能从这个(非常冗长的)示例中看到使用接口来帮助封装特定功能的优势。这允许您将期望从类中获得的功能与类本身分离,并允许使用该类的对象通过接口直接调用它所需的功能。
在我展示的例子中
战斗
不在乎它是否有个性。它所需要知道的是,它有一些可以攻击的东西,也就是实现
内塔克勒
接口。因为我们是这样写的,我们并没有把战斗局限于
Character
s。我们还提供
只反对战斗所必需的东西。这个
内塔克勒
可能会以不同的方式实现,但这没关系,只要
战斗
对象获取所需的信息。
如果在设计中将接口与基类混合使用,那么在构建类层次结构方面就有了一个很好的开端。