假设我具有以下结构:

abstract class Hand {}

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

目标是制作一个函数(或方法)Hand::compareHands(Hand $hand1, Hand $hand2),该函数将在剪刀石头布的比赛中返回获胜的手。

使用一堆if会很容易,但是重点是要有一个更健壮的结构,它依赖于多态性而不是过程代码。

P.S.如果有人问,这是在实际的生产代码中完成的。这不是某种挑战或作业。 (这不是真正的剪刀布,但您明白了)。

最佳答案

您的手的唯一性质是它在击败另一只手。
然后,您不希望在重复使用每种手形的一种具体类型时重复代码,因此需要进行参数化。根据您允许的自由级别,这可以像 protected 成员一样简单:

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旁边)。

关于php - 如何描述三个项目之间的剪刀石头布关系?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12717149/

10-11 19:18