你的手的唯一性质是它正在击败另一只手。
然后你不想重复代码,同时每个手形都有一个具体的类型,所以你需要参数化。根据您可以允许的自由级别,这可以像受保护的成员一样简单:
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 的答案进行比较,谁应该获得实际代码的学分,我只是对其进行了重新排序。但只有很少。
此外,我需要感谢 @Leigh 以获得更好的功能和参数命名。这应该减少评论的需要。
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 旁边)。