Skip to content

Instantly share code, notes, and snippets.

@kencoba
Created February 21, 2012 11:27
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save kencoba/1875983 to your computer and use it in GitHub Desktop.
Save kencoba/1875983 to your computer and use it in GitHub Desktop.
Decorator pattern (Design Patterns in Scala)
// http://en.wikipedia.org/wiki/Decorator_pattern
trait Coffee {
def cost:Double
def ingredients: String
}
class SimpleCoffee extends Coffee {
override def cost = 1
override def ingredients = "Coffee"
}
abstract class CoffeeDecorator(decoratedCoffee: Coffee) extends Coffee {
val sep = ", "
override def cost = decoratedCoffee.cost
override def ingredients = decoratedCoffee.ingredients
}
class Milk(decoratedCoffee: Coffee) extends CoffeeDecorator(decoratedCoffee) {
override def cost = super.cost + 0.5
override def ingredients = super.ingredients + sep + "Milk"
}
class Whip(decoratedCoffee: Coffee) extends CoffeeDecorator(decoratedCoffee) {
override def cost = super.cost + 0.7
override def ingredients = super.ingredients + sep + "Whip"
}
class Sprinkles(decoratedCoffee: Coffee) extends CoffeeDecorator(decoratedCoffee) {
override def cost = super.cost + 0.2
override def ingredients = super.ingredients + sep + "Sprinkles"
}
object DecoratorSample {
def main(args: Array[String]) = {
var c:Coffee = new SimpleCoffee
printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
c = new Milk(c)
printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
c = new Sprinkles(c)
printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
c = new Whip(c)
printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
c = new Sprinkles(c)
printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
}
}
DecoratorSample.main(Array())
@EddieJamsession
Copy link

Sometimes you want to implement decorator in this way:

class Coffee {
  val sep = ", "
  def cost:Double  = 1
  def ingredients: String = "Coffee"
}

trait Milk extends Coffee {
  abstract override def cost = super.cost + 0.5
  abstract override def ingredients = super.ingredients + sep + "Milk"
}

trait Whip extends Coffee {
  abstract override def cost = super.cost + 0.7
  abstract override def ingredients = super.ingredients + sep + "Whip"
}

trait Sprinkles extends Coffee {
  abstract override def cost = super.cost + 0.2
  abstract override def ingredients = super.ingredients + sep + "Sprinkles"
}

object DecoratorSample {
  def main(args: Array[String]) {
    var c: Coffee = new Coffee with Sprinkles
    printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
    c = new Coffee with Sprinkles with Milk
    printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
    c = new Coffee with Sprinkles with Milk with Whip
    printf("Cost: %f Ingredients %s\n", c.cost, c.ingredients)
  }
}

DecoratorSample.main(Array())

@ryantheleach
Copy link

@EddieJamsession If the decorated coffee can't be modified at runtime it doesn't really fit the decorator pattern.

@Ehsan1997
Copy link

Ehsan1997 commented Nov 8, 2017

@EddieJamsession, You should remove this comment, as it is misleading. You are clearly violating ISP.

@jeffxu71
Copy link

Can I buy a coffee with milk and sprinkle in the main()?

@afrat
Copy link

afrat commented Jul 13, 2018

@Ehsan1997 Can't see your point about violating ISP. ISP says that no implementation should depend on unecessary functionality this ist clearly not the case by using mixin compositions in this scenario.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment