假设我有以下结构:
abstract class Hand {}
class Rock extends Hand {}
class Paper extends Hand {}
class Scissors extends Hand {}
我们的目标是制作一个功能(或方法)Hand::compareHands(Hand $hand1, Hand $hand2)
,这将在一个石头剪刀比赛中返回获胜的手。
对于一堆if
来说,这将是非常容易的,但关键是要有一个更强大的结构,这依赖于多态而不是程序代码。
P.S。如果有人问,这是在实际的生产代码中完成的。这不是某种挑战或家庭作业。 (这不是真正的石头剪刀,但你明白了。)
答案 0 :(得分: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旁边)。
答案 1 :(得分:5)
这个怎么样?
class Scissors extends Hand implements Beats<Paper> {}
其中Beats&lt;&gt;是一个通用接口,其签名如下:
interface Beats<Hand> {}
答案 2 :(得分:3)
来自PHP聊天
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;
}