Ответ 1
Единственная природа вашей руки состоит в том, что она избивает один другой.
Затем вы хотите не повторять код, имея один конкретный тип для каждой руки, поэтому вам нужно параметризовать. В зависимости от уровня свободы, который вы можете разрешить, это может быть так же просто, как защищенный член:
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 answer, который должен получить кредиты за фактический код, я просто немного отсортировал его. Но только очень мало.
Кроме того, мне нужно предоставить кредиты @Leigh для лучшей функции и именования параметров. Это должно уменьшить потребность в комментариях.
Вторая альтернатива, предложенная Лузистаном, может быть представлена с помощью шаблона стратегии. Это также несколько прямолинейно:
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 (рядом с Лузистаном).