Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign of decorator pattern #12

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/main/kotlin/Command/base/Cart.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package Command.base

import Decorator.littlekai.base.IngredientDecorator
import Decorator.littlekai.base.Noodles
import Decorator.littlekai.base.SauceDecorator
import Decorator.littlekai.ingredients.Chicken
import Decorator.littlekai.ingredients.Peanuts
import Decorator.littlekai.ingredients.Pork
import Decorator.littlekai.ingredients.Tuna
import Decorator.littlekai.noodles.EggNoodles
import Decorator.littlekai.noodles.UdonNoodles
import Decorator.littlekai.noodles.WheatNoodles
import Decorator.littlekai.sauces.BittersweetSauce
import Decorator.littlekai.sauces.RedPepperSauce
import Decorator.littlekai.sauces.SateSauce
Expand Down Expand Up @@ -79,7 +77,11 @@ open class Cart(private val scanner: Scanner) {
}

fun showPrice() {
println("> Your order is: ${noodles.calculateCost()} $")
var totalCost = noodles.calculateCost()
if (noodles is IngredientDecorator) {
totalCost = (noodles as IngredientDecorator).calculateTotalCost()
}
println("> Your order is: $totalCost $")
if (noodles is SauceDecorator) {
println("> Spiciness is: ${(noodles as SauceDecorator).SPICINESS} out of 4")
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package Decorator.littlekai.base

abstract class IngredientDecorator (private val noodles: Noodles) : Noodles by noodles {
protected abstract val COST : Double

override fun calculateCost(): Double = noodles.calculateCost() + this.COST
abstract class IngredientDecorator (private val noodles: Noodles): Noodles by noodles {
override fun calculateTotalCost(): Double = noodles.calculateTotalCost()
}
3 changes: 2 additions & 1 deletion src/main/kotlin/Decorator/littlekai/base/Noodles.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package Decorator.littlekai.base

interface Noodles {
fun calculateCost() : Double
fun calculateCost(): Double
fun calculateTotalCost(): Double
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then IngredientDecorator is not adding any behaviour 😵

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with the fact of implementing the decorator function in each concrete case, it's already adding behaviour. What do you think about it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But If Noodles already has a method calculateTotalCost() then, every child that implements it modifies its behaviour. Noodles shouldn't have that method, it belongs to IngredientDecorator and the concrete decorators which will add that behaviour to Noodles.

}
2 changes: 1 addition & 1 deletion src/main/kotlin/Decorator/littlekai/base/SauceDecorator.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package Decorator.littlekai.base

abstract class SauceDecorator(private val noodles: Noodles) : Noodles by noodles {
abstract class SauceDecorator(private val noodles: Noodles): Noodles by noodles {
abstract val SPICINESS: Int
}
4 changes: 2 additions & 2 deletions src/main/kotlin/Decorator/littlekai/ingredients/Chicken.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import Decorator.littlekai.base.IngredientDecorator
import Decorator.littlekai.base.Noodles


class Chicken(noodles: Noodles) : IngredientDecorator(noodles) {
override val COST: Double = 3.50
class Chicken(noodles: Noodles, val COST: Double = 3.50): IngredientDecorator(noodles) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COST is a constant. It shouln't go in the constructor because you are opening it to change and we are not interested in that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the keyword val make the constant COST inmutable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you are placing the declaration in the constructor. You are giving the opportunity to set another COST when making a new instance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done some tests and you're right. I have extracted the COST variable from the constructor to an immutable constant.

override fun calculateTotalCost(): Double = super.calculateTotalCost() + COST
}
4 changes: 2 additions & 2 deletions src/main/kotlin/Decorator/littlekai/ingredients/Peanuts.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import Decorator.littlekai.base.IngredientDecorator
import Decorator.littlekai.base.Noodles


class Peanuts(noodles: Noodles) : IngredientDecorator(noodles) {
override val COST: Double = 2.50
class Peanuts(noodles: Noodles, val COST: Double = 2.50): IngredientDecorator(noodles) {
override fun calculateTotalCost(): Double = super.calculateTotalCost() + COST
}
4 changes: 2 additions & 2 deletions src/main/kotlin/Decorator/littlekai/ingredients/Pork.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import Decorator.littlekai.base.IngredientDecorator
import Decorator.littlekai.base.Noodles


class Pork(noodles: Noodles) : IngredientDecorator(noodles) {
override val COST: Double = 4.00
class Pork(noodles: Noodles, val COST: Double = 4.00): IngredientDecorator(noodles) {
override fun calculateTotalCost(): Double = super.calculateTotalCost() + COST
}
4 changes: 2 additions & 2 deletions src/main/kotlin/Decorator/littlekai/ingredients/Tuna.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import Decorator.littlekai.base.IngredientDecorator
import Decorator.littlekai.base.Noodles


class Tuna(noodles: Noodles) : IngredientDecorator(noodles) {
override val COST: Double = 2.75
class Tuna(noodles: Noodles, val COST: Double = 2.75): IngredientDecorator(noodles) {
override fun calculateTotalCost(): Double = super.calculateTotalCost() + COST
}
7 changes: 3 additions & 4 deletions src/main/kotlin/Decorator/littlekai/noodles/EggNoodles.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package Decorator.littlekai.noodles

import Decorator.littlekai.base.Noodles

class EggNoodles : Noodles {
private val COST : Double = 3.75

override fun calculateCost(): Double = this.COST
class EggNoodles(val COST: Double = 3.75): Noodles {
override fun calculateCost(): Double = COST
override fun calculateTotalCost(): Double = COST
}
7 changes: 3 additions & 4 deletions src/main/kotlin/Decorator/littlekai/noodles/UdonNoodles.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package Decorator.littlekai.noodles

import Decorator.littlekai.base.Noodles

class UdonNoodles : Noodles {
private val COST : Double = 4.00

override fun calculateCost(): Double = this.COST
class UdonNoodles(val COST: Double = 4.00): Noodles {
override fun calculateCost(): Double = COST
override fun calculateTotalCost(): Double = COST
}
7 changes: 3 additions & 4 deletions src/main/kotlin/Decorator/littlekai/noodles/WheatNoodles.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package Decorator.littlekai.noodles

import Decorator.littlekai.base.Noodles

class WheatNoodles : Noodles {
private val COST : Double = 3.50

override fun calculateCost(): Double = this.COST
class WheatNoodles(val COST: Double = 3.50): Noodles {
override fun calculateCost(): Double = COST
override fun calculateTotalCost(): Double = COST
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package Decorator.littlekai.sauces
import Decorator.littlekai.base.Noodles
import Decorator.littlekai.base.SauceDecorator

class BittersweetSauce(noodles: Noodles) : SauceDecorator(noodles) {
class BittersweetSauce(noodles: Noodles): SauceDecorator(noodles) {
override val SPICINESS: Int = 1
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import Decorator.littlekai.base.Noodles
import Decorator.littlekai.base.SauceDecorator


class RedPepperSauce(noodles: Noodles) : SauceDecorator(noodles) {
class RedPepperSauce(noodles: Noodles): SauceDecorator(noodles) {
override val SPICINESS: Int = 4
}
2 changes: 1 addition & 1 deletion src/main/kotlin/Decorator/littlekai/sauces/SateSauce.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package Decorator.littlekai.sauces
import Decorator.littlekai.base.Noodles
import Decorator.littlekai.base.SauceDecorator

class SateSauce(noodles: Noodles) : SauceDecorator(noodles) {
class SateSauce(noodles: Noodles): SauceDecorator(noodles) {
override val SPICINESS: Int = 2
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import Decorator.littlekai.base.Noodles
import Decorator.littlekai.base.SauceDecorator


class TeriyakiSauce(noodles: Noodles) : SauceDecorator(noodles) {
class TeriyakiSauce(noodles: Noodles): SauceDecorator(noodles) {
override val SPICINESS: Int = 0
}
30 changes: 17 additions & 13 deletions src/test/kotlin/Decorator/littlekai/base/IngredientDecoratorTest.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
package Decorator.littlekai.base

import Decorator.littlekai.ingredients.Chicken
import Decorator.littlekai.ingredients.Peanuts
import Decorator.littlekai.ingredients.Pork
import Decorator.littlekai.ingredients.Tuna
import Decorator.littlekai.noodles.EggNoodles
import Decorator.littlekai.noodles.UdonNoodles
import Decorator.littlekai.noodles.WheatNoodles
import org.hamcrest.CoreMatchers.`is`
import org.junit.Assert.assertThat
import Decorator.littlekai.sauces.BittersweetSauce
import org.junit.Assert.assertTrue
import org.junit.Test

class IngredientDecoratorTest {

@Test
fun `check if decorated element is still Noodles`() =
assertTrue(Pork(UdonNoodles()) is Noodles) //:+1:
fun `has the same interface`() =
assertTrue(BittersweetSauce(Chicken(EggNoodles())) is Noodles)

@Test
fun `Ingredient Decorator should return ingredient cost plus base noodle cost`() =
assertThat(Pork(UdonNoodles()).calculateCost(), `is`(8.00))
fun `does not modify behavior`() =
assertTrue(EggNoodles().calculateCost() == BittersweetSauce(Chicken(EggNoodles())).calculateCost())

@Test
fun `check decorated Noodles is of type IngredientDecorator`() =
assertTrue(Tuna(UdonNoodles()) is IngredientDecorator)
fun `adds behavior`() =
assertTrue(Chicken(EggNoodles()).calculateTotalCost() == EggNoodles().calculateCost() + Chicken(EggNoodles()).COST)

@Test
fun `price of ingredient is calculated correctly`() =
assertThat(Tuna(Pork(UdonNoodles())).calculateCost(), `is`(10.75))

fun `is stackable`() =
assertTrue(
Tuna(Pork(Peanuts(Chicken(EggNoodles())))).calculateTotalCost() ==
EggNoodles().COST +
Chicken(EggNoodles()).COST +
Peanuts(EggNoodles()).COST +
Pork(EggNoodles()).COST +
Tuna(EggNoodles()).COST)
}