如何描述3件物品之间的石头 - 剪刀关系?

Mad*_*iha 12 php oop

假设我有以下结构:

abstract class Hand {}

class Rock extends Hand {}
class Paper extends Hand {}
class Scissors extends Hand {}
Run Code Online (Sandbox Code Playgroud)

目标是制作一个功能(或方法)Hand::compareHands(Hand $hand1, Hand $hand2),它将在一个石头剪刀比赛中返回获胜的手.

对于一堆ifs来说,这将是非常容易的,但关键是要有一个更强大的结构,这依赖于多态而不是程序代码.

PS这是在实际的生产代码中完成的,如果有人问的话.这不是某种挑战或家庭作业.(这不是真正的石头剪刀,但你明白了).

hak*_*kre 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';
}
Run Code Online (Sandbox Code Playgroud)

我认为这是标准模板方法模式,以一种非常简单的形式.

将此与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'
    )
);
Run Code Online (Sandbox Code Playgroud)

两只手之间的比较已被完全封装成EvaluateHands甚至可配置的类型(如果游戏规则改变),而双手将保持不变:

abstract class Hand {}

class Rock extends Hand {}

class Paper extends Hand {}

class Scissors extends Hand {}
Run Code Online (Sandbox Code Playgroud)

此代码的积分将转至gordon(Lusistanian旁边).

  • 啊好吧,是的,可以在这里记录逻辑(特别是`compareHand`的返回值).但是我认为更重要的是展示如何使用抽象函数和受保护成员来使其工作.具体算法并不重要(正如OP所写的那样).`compareHand`是bool并判断与(参数)比较的手牌是否被击败. (2认同)

Chr*_*nte 5

这个怎么样?

class Scissors extends Hand implements Beats<Paper> {}
Run Code Online (Sandbox Code Playgroud)

其中Beats <>是一个通用接口,其签名如下:

interface Beats<Hand> {}
Run Code Online (Sandbox Code Playgroud)