2012-10-03 50 views
12

Digamos que tienen la siguiente estructura:¿Cómo se puede describir una relación roca-papel-tijera entre 3 artículos?

abstract class Hand {} 

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

El objetivo es hacer una función (o un método) Hand::compareHands(Hand $hand1, Hand $hand2), lo que devolvería la mano ganadora en un partido de piedra-papel-tijeras.

Eso sería muy fácil con un montón de if s, pero el punto es tener una estructura más robusta, que se basa en el polimorfismo en lugar de en el código de procedimiento.

P.S. esto se hace en código de producción real, si alguien está preguntando. Esto no es un tipo de desafío o tarea. (En realidad no es rock-papel-tijera, pero entiendes el punto).

+0

Las instancias de 'Hand' no se comparan entre sí. Es por eso que tenemos 'Cerebros'. –

+0

@tereko: Interesante, ¿tiene una solución que involucre 'Cerebro'? –

Respuesta

12

La única característica de su mano es que está superando a uno solo.

Luego no desea repetir el código mientras tiene un tipo de concreto por forma de mano, por lo que debe parametrizar. Dependiendo del nivel de libertad puede permitir, esto puede ser tan simple como un miembro protegido:

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'; 
} 

Creo que este es el plantilla de patrón estándar método aquí, en una forma muy simple.

Compara esto con Lusitanian's answer que debería obtener los créditos para el código real, simplemente lo he reordenado un poco. Pero solo muy poco.

Además, tengo que dar créditos a @Leigh for the far better function and parameter naming. Esto debería reducir la necesidad de comentarios.

La segunda alternativa que sugiere Lusistanian se puede representar con el patrón de estrategia . Es también un poco hacia adelante recta:

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' 
    ) 
); 

La comparación entre dos manos ha sido totalmente encapsulado en el tipo EvaluateHands que es aún configurable (si las reglas del juego cambian), mientras que las manos se mantienen igual:

abstract class Hand {} 

class Rock extends Hand {} 

class Paper extends Hand {} 

class Scissors extends Hand {} 

Créditos para este código vaya a gordon (al lado de Lusistanian).

+0

Súper hermosa. Creo que la única forma de decepcionarte es la falta de comentarios, pero qué solución más bonita. –

+0

@JohnBallinger: por favor, comparta donde se pierde uno u otro comentario, me complace agregar esos. – hakre

+0

+1, ya que es bastante claro y no uno de marfil. Como nota al margen, quizás sería prudente mostrar resultados diferentes para victorias, empates y derrotas, que verificando tanto '$ hand instanceof $ this-> beats' y' $ this instanceof $ hand-> beats'. – raina77ow

5

¿Qué tal esto?

class Scissors extends Hand implements Beats<Paper> {} 

donde Beats <> es una interfaz genérica cuya firma se parece a:

interface Beats<Hand> {} 
+0

No estoy programando en Java (lo anterior es pseudo código) el código real es PHP. Aunque esto parece interesante, ¿podrías dar más detalles sobre eso? –

+1

Oh, está bien. Sé que PHP agregó rasgos recientemente, que son como interfaces, pero no sé si puede hacer genéricos. Dado que usted preguntó sobre OOP genéricamente, y no sobre PHP específicamente, lo dejo tal como está. –

+1

+1, sin duda la idea correcta – Lusitanian

3

partir de chat PHP

al estilo de programación orientada a objetos

<?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; 
    } 
} 

función simple

<?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

Parece interesante, pero me gustaría intentar y evitar repetir el código una y otra vez. –

Cuestiones relacionadas