2012-12-20 2 views
3

저는 프로그래밍과 OOP에 익숙하지 않기 때문에 저의 부족함을 용서해주세요. 지식. 또한'Rock, Paper, Scissors'에서 VB.NET에서 'Lizard, Spock'을 포함하고 코드를보다 확장 가능하고, 유지 보수가 가능하며 재사용 가능하도록 개선했습니다.

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 

:

내 락의 일환으로, 종이와 가위 게임 나는 추상 슈퍼 클래스처럼 VB.NET에 서브 클래스 ( 록, 종이와 가위)가 ( 무기)가 서브 클래스 ( PlayerComputerRandom을 가진 슈퍼 클래스 Player를PlayerHumanPlayerPlayerComputerTactical)과 같은 :

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 

내가해야 할 것은이 될 것입니다 : 아래 그림과 같이 나는 프런트 엔드에 사용되는 다양한 논리를 개체를 인스턴스화하고 수행하는 GameForm 클래스가

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 

새 무기 (도마뱀, Spock)를 추가 할 수 있습니다. 서브 우물 (Lizard, Spock)을 상속하여 무기를 추가하면됩니다. 기본 클래스.

그러나 실제로는 장기간 유지 관리가 가능한 솔루션이 아닌 모든 하위 클래스 (바위, 종이 및 가위)에 대한 코드 변경이 필요합니다. 물론 모범 사례는 아닙니다.

Im 코딩과 OOP에 새로운 점이있어서 추가 게임을 쉽게 추가 할 수 있도록 기존 게임을 향상시킬 수있는 방법을 친절하게 보여줄 수 있습니까? DB 테이블을 사용하여 무기를 저장할 수 있습니까? 그렇다면 어떻게 보여줄 수 있습니까? 나는이 게임을위한 장기적이고 재사용 가능한 솔루션을 원한다.

어떻게하면 될까요? 어떤 도움이라도 대단히 감사하겠습니다. 사전

답변

1

에서

Manys 덕분에 동적으로는 이해가되지 않습니다 새로운 "서브 클래스"를 추가 할 수있을 것입니다 있지만. "종이"와 "락"(예를 들어)이 다른 클래스로 표시되지 않지만 다른 속성을 가진 같은 클래스로 표시됩니다. 무기의 하나의 속성은 "이름"("바위")이고, 다른 속성은 다른 무기 (이름으로 정의 됨)와 비교되는 속성입니다.

** UPDATED ** 예 :

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 클래스를 추가하고 correspondign 메소드를 구현합니다.

LizardSpock을 추가하는 것은 동일한 단계를 반복하는 것입니다. 여기서 알 수 있듯이 다음과 같은 단점이 있습니다.

  • (+) 기존 동작을 변경하지 않고 동작을 추가합니다 (즉, 기존의 구현 방식을 수정하지 않음). 이는 유지 보수 및 테스트의 관점에서 우수합니다 (테스트는 여전히 작동해야 함).
  • (+) 이것은 개인적인 취향에 달려 있지만, switch 문을 단일 메서드로 분리하면 더 이해할 수 있습니다.
  • (-) 메소드 폭발이 있습니다. 이것은 double dispatching의 널리 알려진 부작용이며 새로운 변형을 추가한다는 것은 다른 모든 클래스에 새 메서드를 추가한다는 것을 의미합니다.

마지막으로 정수를 반환하지는 않지만 실제로 결과를 객체 (Win/Loose/Tie)로 모델링 할 수 있습니다. 이렇게하면 switch 문 대신에 결과에 동작을 위임 할 수 있습니다.

HTH

관련 문제