Skip to content

Instantly share code, notes, and snippets.

@telless
Created March 23, 2018 12:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save telless/a5f961aeffa06a937086388ec0099c26 to your computer and use it in GitHub Desktop.
Save telless/a5f961aeffa06a937086388ec0099c26 to your computer and use it in GitHub Desktop.
<?php
abstract class Calculatable
{
const SUBTRACT_ACTION = 'subtract';
const SUBTRACT_SYMBOL = '-';
const ADD_ACTION = 'add';
const ADD_SYMBOL = '+';
public function add(Calculatable $child): Calculatable
{
return $this->action($child, self::ADD_ACTION);
}
public function subtract(Calculatable $child): Calculatable
{
return $this->action($child, self::SUBTRACT_ACTION);
}
abstract protected function action(Calculatable $child, string $action): Calculatable;
public function asFloat(): float
{
return $this->calculate();
}
public function describe(): string
{
return $this->buildFormula();
}
abstract protected function calculate(): float;
abstract protected function buildFormula(): string;
}
class Calculation extends Calculatable
{
private $firstElement;
private $action;
private $secondElement;
public function __construct(Calculatable $firstElement, string $action, Calculatable $secondElement)
{
$this->firstElement = $firstElement;
$this->action = $action;
$this->secondElement = $secondElement;
}
protected function action(Calculatable $child, string $action): Calculatable
{
$calculation = new Calculation($this, $action, $child);
return $calculation;
}
/**
* @throws Exception
*/
protected function getActionSymbol(): string
{
switch ($this->action) {
case self::ADD_ACTION:
return self::ADD_SYMBOL;
break;
case self::SUBTRACT_ACTION:
return self::SUBTRACT_SYMBOL;
break;
default:
throw new Exception("action {$this->action} was not implemented");
}
}
/**
* @throws Exception
*/
protected function calculate(): float
{
$firstCalc = $this->firstElement->calculate();
$secondCalc = $this->secondElement->calculate();
if ($this->action == self::SUBTRACT_ACTION) {
return $firstCalc - $secondCalc;
} elseif ($this->action == self::ADD_ACTION) {
return $firstCalc + $secondCalc;
} else {
throw new Exception("action {$this->action} was not implemented");
}
}
/**
* @throws Exception
*/
protected function buildFormula(): string
{
$firstElement = $this->firstElement->buildFormula();
$secondElement = $this->secondElement->buildFormula();
$actionSymbol = $this->getActionSymbol();
return "({$firstElement} {$actionSymbol} {$secondElement})";
}
}
Class Money extends Calculatable
{
private $value;
public function __construct(float $value)
{
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
protected function calculate(): float
{
return $this->getValue();
}
protected function action(Calculatable $child, string $action): Calculatable
{
return new Calculation($this, $action, $child);
}
protected function buildFormula(): string
{
return "{$this->getValue()}";
}
}
function Money($value)
{
return new Money($value);
}
$a = Money(10.0)->add(Money(20.0))->subtract(Money(5.0));
$b = Money(40.0)->subtract($a->subtract(Money(3.0)));
$c = Money(20)->add($b)->subtract($a);
echo $a->asFloat().PHP_EOL; // 25.0
echo $a->describe().PHP_EOL; // ((10 + 20) – 5)
echo $b->asFloat().PHP_EOL; // 18.0
echo $b->describe().PHP_EOL; // (40.0 – (((10 + 20) - 5) – 3))
echo $c->asFloat().PHP_EOL; // 13
echo $c->describe().PHP_EOL; // ((20 + (40 - (((10 + 20) - 5) - 3))) - ((10 + 20) - 5))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment