var Vodka = function() { if (this.constructor === Vodka) { throw new Error("Abstract"); } }; Vodka.prototype.getBrand = function() { if (this.brand === undefined) { this.brand = "Undefined Vodka Brand"; } return this.brand; } Vodka.prototype.calculatePrice = function() { throw new Error("Abstract Method"); } var GreyGoose = function(brand) { Vodka.apply(this, arguments); this.brand = brand; }; GreyGoose.prototype = Object.create(Vodka.prototype); GreyGoose.prototype.constructor = GreyGoose; GreyGoose.prototype.calculatePrice = function() { return 32.99; }; var VodkaDecorator = function() { if (this.constructor === VodkaDecorator) { throw new Error("Abstract"); } }; VodkaDecorator.prototype.sizePrice = function(size) { throw new Error("Abstract Method"); }; VodkaDecorator.prototype.getBrand = function() { throw new Error("Abstract Method"); }; VodkaDecorator.prototype.calculatePrice = function() { throw new Error("Abstract Method"); } var RedBull = function(drink, size) { this.drink = drink; this.size = size; this.price = this.sizePrice(size); } RedBull.prototype = Object.create(VodkaDecorator.prototype); RedBull.prototype.constructor = RedBull; RedBull.prototype.sizePrice = function(size) { return function() { var price; switch (size) { case "Small": price = 2.99; break; case "Medium": price = 4.99; break; case "Large": price = 6.99; break; default: price = 8.99; // unknown size - super wings break; } return price; }(); // private method by closure }; RedBull.prototype.getBrand = function() { return this.drink.getBrand() + "\nand a " + this.size + " Red Bull which gives you wings for $" + this.price; }; RedBull.prototype.calculatePrice = function() { return this.price + this.drink.calculatePrice(); }; var main = (function() { var drink = new GreyGoose('Grey Goose'); alert(drink.getBrand() + " $" + drink.calculatePrice()); var mixedDrink = new RedBull(drink, "Large"); alert(mixedDrink.getBrand() + "\nTotal price is: $" + mixedDrink.calculatePrice()); })();