Pour PetitePeste j'étais en train d'y réfléchir justement, je savais que j'avais viré une étape et je regardais le code du phpTour car je pensais qu'il avait trouvé un autre moyen de faire, donc voici le mien :
<?php
interface GiveGoldByHero
{
public function giveGoldByHero(Gold $gold, Hero $hero);
}
interface Kid extends GiveGoldByHero { }
interface Women extends GiveGoldByHero
{
public function ageIsAskedByHero(Hero $hero);
}
interface WomenKid extends Women, Kid { }
interface Hero
{
public function askGoldByWomen(Women $women);
public function askGoldByKid(Kid $kid);
public function askGoldByWomenKid(WomenKid $womenKid);
public function ageOfWomenIs(Age $age);
}
final class Age
{
private $value;
public function __construct($value)
{
if (is_integer($value) === false) {
throw new RuntimeException('Age value should be construct from an integer');
}
if ($value < 0) {
throw new RuntimeException('Age value should be greater than or equal to 0');
}
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
public function executeIfGreaterOrEqualTo(callable $callable, self $age)
{
if ($this->value >= $age->value) {
$callable();
}
return $this;
}
}
final class Gold
{
private $value;
public function __construct($value)
{
if (is_integer($value) === false) {
throw new RuntimeException('Gold value should be construct from an integer');
}
if ($value < 0) {
throw new RuntimeException('Gold value should be greater than or equal to 0');
}
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
}
class Conan implements Hero
{
private $gold;
private $giveGold = false;
public function __construct(Gold $gold)
{
$this->gold = $gold->getValue();
}
public function askGoldByWomen(Women $women)
{
if ($this->gold < 2) {
return;
}
$hero = clone $this;
$hero->giveGold = false;
$women->ageIsAskedByHero($hero);
if ($hero->giveGold === true) {
$this->gold = $this->gold - 2;
$women->giveGoldByHero(new Gold(2), $hero);
echo "[Hero] I still have " . $this->gold . " gold\n";
}
}
public function askGoldByKid(Kid $kid)
{
if ($this->gold < 1) {
return;
}
$this->gold = $this->gold - 1;
$hero->giveGold = false;
$kid->giveGoldByHero(new Gold(1), $this);
echo "[Hero] I still have " . $this->gold . " gold\n";
}
public function askGoldByWomenKid(WomenKid $womenKid)
{
if ($this->gold === 0) {
return;
}
$hero = clone $this;
$hero->giveGold = false;
$womenKid->ageIsAskedByHero($hero);
if ($hero->giveGold === true) {
$gold = $this->gold;
$this->gold = 0;
$womenKid->giveGoldByHero(new Gold($gold), $hero);
echo "[Hero] I still have " . $this->gold . " gold\n";
}
}
public function ageOfWomenIs(Age $age)
{
$age->executeIfGreaterOrEqualTo(
function () { $this->giveGold = true; },
new Age(18)
);
}
}
class PetitePeste implements Women {
public function ageIsAskedByHero(Hero $hero) {
}
public function racketer(Hero $hero) {
// Ca pourrait venir d'un autre bout de code:
// Dans un tel cas, bon courage pour débugger
$hero->ageOfWomenIs(new Age(42));
$hero->askGoldByWomen($this);
}
public function giveGoldByHero(Gold $gold, Hero $hero) {
echo "Thanks for your " . $gold->getValue() . " goldcoins, sucker!\n";
}
}
$conan = new Conan(new Gold(300));
$peste = new PetitePeste();
$peste->racketer($conan);
var_dump($conan);