3

我是编程和 OOP 的新手,所以请原谅我缺乏知识。

作为我的 Rock, Paper and Scissors 游戏的一部分,我有一个抽象超类(Weapon ),它在 VB.NET中有子类(Rock, Paper 和 Scissors ),例如:

    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

还有一个超类Player,它具有子类(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 和 Scissors)进行代码更改,这并不是真正的长期可维护解决方案。当然不是最佳做法。

我是编码和 OOP 的新手,有人可以展示我如何增强现有游戏以轻松添加额外的武器吗?我可以使用数据库表来存储武器吗?如果是这样,你能告诉我怎么做吗?我只想为这款游戏提供长期、可重复使用的解决方案。

知道如何实现这一目标吗?任何帮助将不胜感激。

提前谢谢

4

3 回答 3

1

尽管可以动态添加新的“子类”,但它没有意义。只是不要将“Paper”和“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) 的示例,因为在这种特定情况下,“解决方案”会简单得多。

于 2012-12-20T09:28:43.703 回答
0

如果这有助于您可以为您的类编写运算符以进行比较和其他 Ex ,那也是一回事:

#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
于 2012-12-20T11:11:27.653 回答
0

一种广泛使用的方法是双重调度。当您需要定义依赖于两个不同类的行为(或返回值)时,您可以应用此方法。您无需创建 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只是重复相同的步骤。如您所见,这里有一些权衡:

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

As a final note you may consider not returning an integer but to actually model your result as an object (Win/Loose/Tie). By doing so you can then delegate behavior to the result instead fo making switch statements over it.

HTH

于 2012-12-20T11:29:03.167 回答