2012-12-20 75 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