2012-10-03 3 views
12

의 나는 다음과 같은 구조를 가지고 있다고 가정 해 봅시다 :3 항목 사이에 바위 종이 가위 관계를 어떻게 설명 할 수 있습니까?

abstract class Hand {} 

class Rock extends Hand {} 
class Paper extends Hand {} 
class Scissors extends Hand {} 

목표는 가위 바위 보 경기에서 승리 손을 반환하는 함수 (또는 방법) Hand::compareHands(Hand $hand1, Hand $hand2)를 만드는 것입니다.

if을 사용하면 매우 쉽지만 요점은 절차 코드보다는 다형성에 의존하는보다 견고한 구조를 갖는 것입니다.

P. 누군가가 요구하는 경우 실제 생산 코드에서이 작업이 수행됩니다. 이것은 일종의 도전이나 숙제가 아닙니다. (실제로 바위 종이 가위가 아니지만, 당신은 요점을 얻는다.)

+0

'손'의 인스턴스는 자신을 비교하지 않습니다. 그래서 우리는 '뇌'를 가지고 있습니다. –

+0

@tereko : 흥미 롭다면, '뇌'와 관련된 해결책이 있습니까? –

답변

12

손의 유일한 성격은 하나의 다른 하나를 때리고 있다는 것입니다.

그런 다음 코드를 반복하지 않으려면 손 모양마다 구체적인 유형이 필요하므로 매개 변수화가 필요합니다. 당신은 할 수 있습니다 자유의 수준에 따라,이 보호 구성원으로 간단 할 수 있습니다

abstract class Hand { 

    protected $beats; 

    final public function beats(Hand $opponent) { 

     return $opponent instanceof $this->beats; 
    } 
} 

class Rock extends Hand { 

    protected beats = 'Scissors'; 
} 

class Paper extends Hand { 

    protected beats = 'Rock'; 
} 

class Scissors extends Hand { 

    protected beats = 'Paper'; 
} 

나는 이것이 매우 간단한 형태로 여기에 표준 템플릿 메소드 패턴,라고 생각합니다.

실제 코드에 대한 크레딧을 받아야하는 Lusitanian's answer과 비교해보십시오. 조금만 다시 정렬했습니다. 그러나 단지 아주 조금.

또한 @Leigh for the far better function and parameter naming에게 크레딧을 제공해야합니다. 이렇게하면 의견이 줄어 듭니다.

Lusistanian이 제안하는 두 번째 대안은 전략 패턴으로 나타낼 수 있습니다. 또한 다소 정직 :

class EvaluateHands 
{ 
    private $rules; 

    public function __construct(array $rules) 
    { 
     $this->rules = $rules; 
    } 

    public function compareHands(Hand $hand1, Hand $hand2) 
    { 
     return $this->rules[get_class($hand1)] === get_class($hand2) ? $hand1 : $hand2; 
    } 
} 

new EvaluateHands(
    array(
     'Rock' => 'Scissors', 
     'Paper' => 'Rock', 
     'Scissor' => 'Paper' 
    ) 
); 

두 손 사이의 비교는 완전히도 구성 가능하다 EvaluateHands 형식으로 캡슐화 된 (만약 게임 변화의 규칙) 손이 동일하게 유지 할 동안, :

abstract class Hand {} 

class Rock extends Hand {} 

class Paper extends Hand {} 

class Scissors extends Hand {} 

이 코드에 대한 크레딧은 gordon (Lusistanian 옆)으로 이동하십시오.

+0

슈퍼 아름다운. 내가 너를 실망시킬 수있는 유일한 방법은 의견이 부족하지만 아주 예쁜 해결책이라고 생각한다. –

+0

@JohnBallinger : 한 가지 또는 다른 의견을 놓친 부분을 공유하십시오. 추가 할 수있어서 기쁩니다. – hakre

+0

+1, 그것은 분명하고 상아탑이 아닙니다. 사이드 노트로, 아마도 $ hand instanceof $ this-> beats와 $ this instanceof $ hand-> beats를 검사하는 승패와 패배에 대해 다른 결과를 보여주는 것이 현명 할 것입니다. – raina77ow

5

어때? < 낫지>

class Scissors extends Hand implements Beats<Paper> {} 

누구의 서명이 보이는 일반적인 인터페이스와 같은 : PHP 채팅에서

interface Beats<Hand> {} 
+0

나는 자바로 프로그래밍하지 않고있다. (위 코드는 의사 코드이다.) 실제 코드는 PHP 다. 이것은 흥미로운 것 같지만, 그것에 대해 자세히 설명해 주시겠습니까? –

+1

오, 오케이. 나는 PHP가 최근에 인터페이스와 같은 특성을 추가했다는 것을 알고 있지만 generics를 수행 할 수 있는지 여부는 모른다. OOP에 관해서는 PHP가 아닌 일반적으로 묻는 것이므로, 그대로 두겠습니다. –

+1

+1, 물론 올바른 생각 – Lusitanian

3

OOP 스타일

<?php 
interface Hand { 
    function beats(Hand $hand); 
} 

class Rock implements Hand { 
    public function beats(Hand $hand) { 
     return $hand instanceof Scissors; 
    } 
} 
class Paper implements Hand { 
    public function beats(Hand $hand) { 
     return $hand instanceof Rock; 
    } 
} 

class Scissors implements Hand { 
    public function beats(Hand $hand) { 
     return $hand instanceof Paper; 
    } 
} 

간단한 기능

<?php 
const PAPER = 1; 
const ROCK = 2; 
const SCISSORS = 3; 

function whichHandWon($hand1, $hand2) { 
    $winners = [PAPER => ROCK, ROCK => SCISSORS, SCISSORS => PAPER]; 
    return intval($winners[$hand1] !== $hand2) + 1; 
} 
+0

흥미 롭군요.하지만 반복해서 코드를 반복하지 않으려 고합니다. –

관련 문제