2012-12-20 76 views
3

我是编程和OOP的新手,请原谅我缺乏知识。在VB.NET中增加'Rock,Paper,Scissors'以包含'Lizard,Spock',并且使代码更具可扩展性,可维护性和可重用性

正如我岩石的一部分,剪刀布的游戏我有一个抽象超(武器),其中有子类(岩石,纸和剪刀)在VB.NET,如:

Public MustInherit Class Weapons 
     Public MustOverride Function compareTo(ByVal Weapons As Object) As Integer 

    End Class 

    Public Class Paper 
     Inherits Weapons 

     Public Overrides Function compareTo(ByVal Weapons As Object) As Integer 
      If TypeOf Weapons Is Paper Then 
       Return 0 
      ElseIf TypeOf Weapons Is Rock Then 
       Return 1 
      Else 
       Return -1 
      End If 
     End Function 
    End Class 

    Public Class Rock 
     Inherits Weapons 

     Public Overrides Function compareTo(ByVal Weapons As Object) As Integer 
      If TypeOf Weapons Is Rock Then 
       Return 0 
      ElseIf TypeOf Weapons Is Scissors Then 
       Return 1 
      Else 
       Return -1 
      End If 
     End Function 
    End Class 

    Public Class Scissors 
     Inherits Weapons 

     Public Overrides Function compareTo(ByVal Weapons As Object) As Integer 
      If TypeOf Weapons Is Scissors Then 
       Return 0 
      ElseIf TypeOf Weapons Is Paper Then 
       Return 1 
      Else 
       Return -1 
      End If 
     End Function 
    End Class 

而且有一个超球员其中有子类(PlayerComputerRandomPlayerHumanPlayerPlayerComputerTactical)像:

Imports RockPaperScissors.Weapons 

Public Class Player 

    Private pName As String 
    Private pNumberOfGamesWon As String 
    Public pWeapon As Weapons 

    Property Name() As String 
     Get 
      Return pName 
     End Get 
     Set(ByVal value As String) 
      pName = value 
     End Set 
    End Property 

    Property NumberOfGamesWon As String 
     Get 
      Return pNumberOfGamesWon 
     End Get 
     Set(ByVal value As String) 
      pNumberOfGamesWon = value 
     End Set 
    End Property 

    Property getWeapon As Weapons 
     Get 
      Return pWeapon 
     End Get 
     Set(ByVal value As Weapons) 
      pWeapon = value 
     End Set 
    End Property 

    Public Sub pickWeapon(ByVal WeaponType As String) 
     If WeaponType = "Rock" Then 
      pWeapon = New Rock() 

     ElseIf WeaponType = "Paper" Then 
      pWeapon = New Paper() 

     Else 
      pWeapon = New Scissors() 

     End If 

    End Sub 

End Class 



    Imports RockPaperScissors.Weapons 

Public Class PlayerComputerRandom 
    Inherits Player 

    Private Enum weaponsList 
     Rock 
     Paper 
     Scissors 
    End Enum 

    Public Overloads Sub pickWeapon() 

     Dim randomChoice = New Random() 
     Dim CompChoice As Integer = randomChoice.Next(0, [Enum].GetValues(GetType(weaponsList)).Length) 

     If CompChoice = "0" Then 
      pWeapon = New Rock() 

     ElseIf CompChoice = "1" Then 
      pWeapon = New Paper() 

     Else 
      pWeapon = New Scissors() 

     End If 


    End Sub 

End Class 



Public Class PlayerComputerTactical 
    Inherits Player 

    Private plastMove As String 

    Property lastMove() As String 
     Get 
      Return plastMove 
     End Get 
     Set(ByVal value As String) 
      plastMove = value 
     End Set 
    End Property 

    Public Overloads Sub pickWeapon() 
     ' Add tactical player functionality 
    End Sub 


End Class 


    Public Class PlayerHumanPlayer 
     Inherits Player 

    End Class 

我有GameForm类实例化的对象,并且执行用于前端的各种其它逻辑,如下所示:

Public Class GameForm 
    Private Sub btnRock_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRock.Click 
     findWinner("HumanPlayer", "Rock", "RandomComputer") 
    End Sub 

    Private Sub btnPaper_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPaper.Click 
     findWinner("HumanPlayer", "Paper", "RandomComputer") 
    End Sub 


    Private Sub btnScissors_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnScissors.Click 
     findWinner("HumanPlayer", "Scissors", "RandomComputer") 
    End Sub 

    Public Sub findWinner(ByVal p1name As String, ByVal p1WeaponSelected As String, ByVal p2Name As String) 
     Dim player1 = New PlayerHumanPlayer() 
     Dim player2 = New PlayerComputerRandom() 

     player1.Name = p1name 
     player1.pickWeapon(p1WeaponSelected) ' Should I be using the Rock Class??? 

     player2.Name = p2Name 
     player2.pickWeapon() 

     Dim winner As Integer = player1.getWeapon().compareTo(player2.getWeapon()) 

     Select Case winner 
      Case 1 
       txtGameStatus.Text = player1.Name() + " wins!" 
      Case -1 
       txtGameStatus.Text = player2.Name() + " wins!" 
      Case 0 
       txtGameStatus.Text = "Draw!" 
     End Select 
    End Sub 

End Class 

我需要做的是能够添加新武器(蜥蜴,Spock),我知道我可以通过简单地添加子类(蜥蜴,Spock),它继承武器基类。

但是,这将需要更改所有子类的代码(Rock,Paper and Scissors),这不是一个真正的长期可维护解决方案。当然不是最佳实践。

即时通讯编程和面向对象的新方法如此,有人可以善意地表明我可以如何增强现有的游戏,轻松地允许添加额外的武器?我可以使用数据库表来存储武器吗?如果是这样,你能展示一下吗?我只想为这个游戏提供长期的,可重用的解决方案。

任何想法,我可以如何实现这一目标?任何帮助将不胜感激。

提前

回答

1

Manys感谢。虽然这将是可以动态地添加新的“子类”它没有任何意义。只是看不到“纸”和“摇滚”(例如)不同的CLASSES,但作为具有不同属性的同一类。武器的一个属性是“名称”(“Rock”),另一个属性是它与另一个武器(由名称定义)的比较。

** **修订实例:

Private TheData() As String = {"Scissor|Paper,Spock|Lizard,Rock", 
           "Paper|Rock,Spock|Scissor,Lizard", 
           "Rock|Scissor,Lizard|Paper,Spock", 
           "Spock|Rock,Lizard|Scissor,Paper", 
           "Lizard|Scissor,Paper|Rock,Spock"} 

Sub Main() 

    Dim Weapons As New List(Of Weapon) 

    For Each s In TheData 
     Dim spl = s.Split("|"c) 
     Weapons.Add(New Weapon(spl(0), spl(1).Split(","c), spl(2).Split(","c))) 
    Next 

    Dim r As New Random 

    Dim outcome(2) As Integer 
    For i = 1 To 1000000 
     Dim w1 = Weapons(r.Next(Weapons.Count)) 
     Dim w2 = Weapons(r.Next(Weapons.Count)) 
     Dim o = w1.CompareTo(w2) 
     outcome(o + 1) += 1 
    Next i 
    Console.WriteLine("Loose = {0}, Win = {1}, Draw = {2}", outcome(0), outcome(2), outcome(1)) 

    Console.ReadLine() 

End Sub 

End Module 

Public Class Weapon 
Implements IComparable(Of Weapon) 

Public Name As String 
Private StrongerWeapons As List(Of String) 
Private WeakerWeapons As List(Of String) 

Public Sub New(name As String, stronger As IEnumerable(Of String), weaker As IEnumerable(Of String)) 
    Me.Name = name 
    StrongerWeapons = New List(Of String)(stronger) 
    WeakerWeapons = New List(Of String)(weaker) 

End Sub 

Public Function CompareTo(other As Weapon) As Integer Implements IComparable(Of Weapon).CompareTo 
    Select Case True 
     Case Me.Name = other.Name : Return 0 
     Case WeakerWeapons.Contains(other.Name) : Return -1 
     Case StrongerWeapons.Contains(other.Name) : Return 1 
     Case Else : Throw New ApplicationException("Error in configuration!") 
    End Select 
End Function 
End Class 

现在你将有一个可配置的 “战斗系统”。

更新的示例显示系统“正在运行”。 TheData是你的配置被“存储”的地方,这可能是在一个文本/ XML文件,数据库或其他。

请注意,这是可配置的一个示例,不适用于Stone/Scissor/Paper(Lizard/Spock),因为在这种情况下,“解决方案”会简单得多。

+0

感谢您的及时回复......我会在午餐时间尝试。所以我认为上面的代码也决定谁是赢家?我如何在GameForm类的findWinner()函数中使用它?有一次,我再次道歉,并且感谢你的支持 – AJsStack

+0

'Weapon'类实现了'IComparable(Of Weapon)',所以你仍然可以使用'CompareTo'来获得胜利者。 – igrimpe

0

还一两件事,如果这有助于你可以写操作为您的类比较和其他 例:

#Region "Operators" 
    Public Shared Operator =(ByVal crD1 As GPSCoordinate, ByVal crD2 As GPSCoordinate) As Boolean 
     Return IsEql(crD1, crD2) 
    End Operator 

    Public Shared Operator <>(ByVal crD1 As GPSCoordinate, ByVal crD2 As GPSCoordinate) As Boolean 
     Return Not IsEql(crD1, crD2) 
    End Operator 

    Private Shared Function IsEql(ByVal crD1 As GPSCoordinate, ByVal crD2 As GPSCoordinate) As Boolean 
     If crD1 Is Nothing And crD2 Is Nothing Then 
      Return True 
     ElseIf Not crD1 Is Nothing And Not crD2 Is Nothing Then 
      Return CBool(crD1.Value = crD2.Value) 
     End If 
     Return False 
    End Function 
#End Region 
0

广泛使用的方法为,这是double dispatching。你应用这个whern你需要定义一个依赖于两个不同类的行为(或返回值)。不是创建switch语句,而是为每个案例创建一条消息,并让每个类决定如何表现。我不熟悉VB,所以请原谅我使用另一种语言,但我认为你会得到的想法:

abstract class Weapon 
{ 
abstract public function compareTo($otherWeapon); 
abstract public function compareToRock(); 
abstract public function compareToPaper(); 
} 

class Rock extends Weapon 
{ 
public function compareTo($otherWeapon) 
{ 
return $otherWeapon->compareToRock(); 
} 

public function compareToRock(){return 0;} 

public function compareToPaper(){return -1;} 
} 

class Paper extends Weapon 
{ 
public function compareTo($otherWeapon) 
{ 
return $otherWeapon->compareToPaper(); 
} 

public function compareToRock(){return 1;} 

public function compareToPaper(){return 0;} 
} 

下一步将是添加的Scissors类,这意味着:

  • 在超类中添加compareToScissors()抽象消息。
  • 在每个子类中添加compareToScissors()实现。
  • 添加Scissors类并实现对应的方法。

添加LizardSpock只是重复相同的步骤。正如你可以看到这里有一些权衡:

  • (+)你正在添加行为,而不是改变现有的(即你没有修改现有的方法实现)。从维护和测试的角度来看,这是很好的(你的测试应该仍然有效)。
  • (+)这更多地取决于个人的品味,但对于我来说,用单一方法分隔开关语句更容易理解。
  • ( - )有一种方法爆炸。这是双重调度的一个广为人知的副作用,并且添加一个新变体意味着在所有其他类中添加一个新方法。

作为最后一点,您可以考虑不返回整数,而是将结果实际建模为对象(Win/Loose/Tie)。通过这样做,您可以将行为委托给结果,而不是将结果转换为结果。

HTH