Last active
August 29, 2015 14:19
-
-
Save mageekguy/6f7339723c12b75bfb2d to your computer and use it in GitHub Desktop.
A teenager want alcool in east oriented manner!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Un barman peut servir un verre d'alcool à un client : | |
1) s'il a plus de 18 ans | |
2) s'il dispose du ou des alcools nécessaires (dans le cas d'un cocktail) en stock. | |
*/ | |
interface barman | |
{ | |
function clientWantAlcoholDrinkOfName(client $client, alcoholDrinkName $alcoholDrinkName); | |
function clientAgeIs(age $age); | |
} | |
interface client | |
{ | |
function barmanIs(barman $barman); | |
function newAlcoholDrink(drink $drink); | |
function ageIsRequiredByBarman(barman $barman); | |
function alcoolDrinkIsRefusedByBarman(barman $barman); | |
} | |
final class quantity | |
{ | |
private | |
$value | |
; | |
function __construct($value) | |
{ | |
$this->value = $value; | |
} | |
function __toString() | |
{ | |
return (string) $this->value; | |
} | |
} | |
final class age | |
{ | |
private | |
$value | |
; | |
function __construct($value) | |
{ | |
$this->value = $value; | |
} | |
function __toString() | |
{ | |
return (string) $this->value; | |
} | |
} | |
final class alcoholDrinkName | |
{ | |
private | |
$value | |
; | |
function __construct($value) | |
{ | |
$this->value = (string) $value; | |
} | |
function __toString() | |
{ | |
return $this->value; | |
} | |
} | |
class drink | |
{ | |
function __construct(alcoholDrinkName $alcoholDrinkName, quantity $quantity) | |
{ | |
$this->name = $alcoholDrinkName; | |
$this->quantity = $quantity; | |
} | |
} | |
class legalBarman implements barman | |
{ | |
private | |
$clientAgeIsLegal, | |
$client | |
; | |
function clientWantAlcoholDrinkOfName(client $client, alcoholDrinkName $alcoholDrinkName) | |
{ | |
(new self)->giveAlcoholDrinkOfNameToClient($alcoholDrinkName, $client); | |
return $this; | |
} | |
function clientAgeIs(age $age) | |
{ | |
if ($this->client) | |
{ | |
$this->clientAgeIsLegal = (string) $age >= 18; | |
} | |
return $this; | |
} | |
private function giveAlcoholDrinkOfNameToClient(alcoholDrinkName $alcoholDrinkName, client $client) | |
{ | |
$this->client = $client; | |
$this->client->ageIsRequiredByBarman($this); | |
if ($this->clientAgeIsLegal) | |
{ | |
$this->client->newAlcoholDrink(new drink($alcoholDrinkName, new quantity(5))); | |
} | |
return $this; | |
} | |
} | |
abstract class teenager implements client | |
{ | |
private | |
$age, | |
$drink | |
; | |
function __construct() | |
{ | |
$this->age = rand(14, 18); | |
} | |
function alcoolDrinkIsRefusedByBarman(barman $barman) | |
{ | |
echo 'Fuck you!' . PHP_EOL; | |
} | |
function newAlcoholDrink(drink $drink) | |
{ | |
echo 'Thanks!' . PHP_EOL; | |
$this->drink = $drink; | |
return $this; | |
} | |
function ageIsRequiredByBarman(barman $barman) | |
{ | |
$barman->clientAgeIs(new age($this->age + (18 - $this->age))); | |
return $this; | |
} | |
} | |
class teenagerWhichLikeMojito extends teenager | |
{ | |
function barmanIs(barman $barman) | |
{ | |
$barman->clientWantAlcoholDrinkOfName($this, new alcoholDrinkName('Mojito')); | |
return $this; | |
} | |
} | |
(new teenagerWhichLikeMojito)->barmanIs(new legalBarman); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@TheSecretSquad : great! Good to know I'm not totally incomprehensible.
@mageekguy:
"If the teenager must also provide its religion to a barman, the method religionIsRequiredByBarman(barman $barman) should be add to the client interface, and the method clientReligionIs(religion $religion) should be add to the barman interface. All classes which implements client interface should be updated accordingly."
This is the very definition of strong coupling - to add a new feature we have to change both sides. We can't really talk about open/closed with two classes that work so closely together.
Let's compare (excuse the syntax; I haven't written any php for over ten years):
One function before:
one function after
conversation before (I'll skip the implementation)
conversation after
Both approaches change both caller and callee simultaneously, neither case preserves a working system until both teenager and barman have been updated (java wouldn't compile, I imagine php throws a runtime error of some sort).
We might be able to make this open closed if certain bits of ascertaining legality were optional, and we had an abstract way of talking about each bit of verification (although you'd have to use double dispatch to keep this logic inside the barman, unless you are in something loosely typed where method dispatch is dynamic).
re: the conversation suggesting the caller has control. In a pure tell don't ask system, control can only ever be held by the object currently acting on a message. Both approaches end up passing the barman exactly the same amount of information in the end (one could argue that the conversational approach might save an underage drinker having to reveal their religion, but that's not exactly high on my list of things to optimize for...).
Making religion tda
I'm just playing here, this is not meant to be a good design, just showing where this principle can lead if you apply it blindly.
before:
after