06-06-2015, 10:29 AM
Et dans un langage qui gère correctement les immutables, l'override des opérateurs, les unions de type, ça donne ça :
trait Hero
{
def askGoldByWomen(women: Women): Hero
def askGoldByKid(kid: Kid): Hero
def askGoldByWomenKid(women: Women with Kid): Hero
def ageIs(age: Age): Hero
}
trait Women
{
def ageIsAskedByHero(hero: Hero): Women
def giveGoldByHero(gold: Gold, hero: Hero): Women
}
trait Kid
{
def ageIsAskedByHero(hero: Hero): Kid
def giveGoldByHero(gold: Gold, hero: Hero): Kid
}
case class Gold(amount: Int) extends Ordered[Gold]
{
require(amount >= 0)
def compare(that: Gold) = amount - that.amount
def +(that: Gold): Gold = new Gold(amount + that.amount)
def -(that: Gold): Gold = new Gold(amount - that.amount)
def *(that: Gold): Gold = new Gold(amount * that.amount)
}
case class Age(value: Int) extends Ordered[Age]
{
require(value >= 0)
def compare(that: Age) = value - that.value
def *(that: Age): Age = new Age(value * that.value)
}
class Conan(var gold: Gold) extends Hero
{
var giveGold: Boolean = false
def askGoldByWomen(women: Women): Hero = {
if (gold < Gold(2)) {
return this
}
val hero = new Conan(gold)
women ageIsAskedByHero hero
if (hero.giveGold == true) {
gold -= Gold(2)
women.giveGoldByHero(Gold(2), hero)
println(s"[Hero] I still have $gold")
}
this
}
def askGoldByKid(kid: Kid): Hero = {
if (gold < Gold(1)) {
return this
}
gold -= Gold(1)
kid giveGoldByHero(Gold(1), this)
println(s"[Hero] I still have $gold")
this
}
def askGoldByWomenKid(womenKid: Women with Kid): Hero = {
if (gold == Gold(0)) {
return this
}
val hero = new Conan(gold)
womenKid ageIsAskedByHero hero
if (hero.giveGold == true) {
womenKid giveGoldByHero(gold, this)
gold = Gold(0)
println(s"[Hero] I still have $gold");
}
this
}
def ageIs(age: Age): Hero = {
if (age >= Age(18)) {
giveGold = true
}
this
}
}
class Gamin(age: Age) extends Kid
{
def ageIsAskedByHero(hero: Hero): Kid = {
hero ageIs age
this
}
def giveGoldByHero(gold: Gold, hero: Hero): Kid = {
println(s"Goood i can buy candies for $gold");
this
}
}
class BBardot(age: Age) extends Women
{
def ageIsAskedByHero(hero: Hero): Women = {
hero ageIs age
this
}
def giveGoldByHero(gold: Gold, hero: Hero): Women = {
println(s"I can feed pet with food cost $gold");
this
}
}
class Gamine(age: Age) extends Women with Kid
{
def ageIsAskedByHero(hero: Hero): Women with Kid = {
hero ageIs age*Age(3)
this
}
def giveGoldByHero(gold: Gold, hero: Hero): Women with Kid = {
println(s"I can trick for $gold");
this
}
}
class PetitePeste(age: Age) extends Women
{
def ageIsAskedByHero(hero: Hero): Women = this
def giveGoldByHero(gold: Gold, hero: Hero): Women = {
println(s"Easyyyy boy i get $gold");
this
}
def racketer(hero: Hero) = {
// Ca pourrait venir d'un autre bout de code:
// Dans un tel cas, bon courage pour débugger
hero ageIs age
hero askGoldByWomen this
}
}
val conan = new Conan(Gold(300))
val peste = new PetitePeste(Age(20))
peste racketer conan
val bbardot = new BBardot(Age(80))
val gamin = new Gamin(Age(10))
val gamine = new Gamine(Age(9))
conan askGoldByWomen bbardot
conan askGoldByKid gamin
conan askGoldByWomenKid gamine