/*=======================================
= DESIGN PATTERNS =
=======================================*/
/*========== Creating Objects with Literals ==========*/
var obj = {
firstName: "Jeremy",
lastName: "McPeak"
};
obj.firstName = "Jeremy";
obj["lastName"] = "McPeak";
var firstName = obj["firstName"];
var lastName = obj.lastName;
Object.defineProperty(obj, "country", {
value: "USA"
});
Object.defineProperties(obj, {
twitter: {
value: "jwmcpeak"
},
email: {
value: "jwmcpeak@wdonline.com"
}
});
/*========== Generating Objects with Object.create() ==========*/
var johnDoe = {
firstName: "John",
lastName: "Doe",
sayName: function() {
return "My name is " + this.firstName + " " + this.lastName;
}
};
var janeDoe = Object.create(johnDoe, {
firstName: {
value: "Jane"
},
greet: {
value: function(person) {
return "Hello, " + person.firstName;
}
}
});
var jimSmith = Object.create(janeDoe, {
firstName: {
value: "Jim"
},
lastName: {
value: "Smith"
}
});
//alert(johnDoe.sayName());
//alert(janeDoe.sayName() + " " + janeDoe.greet(johnDoe));
//alert(jimSmith.sayName() + " " + jimSmith.greet(janeDoe));
console.log(janeDoe.__proto__ === johnDoe);
console.log(jimSmith.__proto__ === janeDoe);
/*========== The Constructor Pattern ==========*/
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.sayName = function() {
return "My name is " + this.firstName + " " + this.lastName;
};
var johnDoe = new Person("John", "Doe");
var janeDoe = new Person("Jane", "Doe");
var isPerson = johnDoe instanceof Person; // true
var isSame = johnDoe.sayName === janeDoe.sayName; // true
/*========== The Inheritance Pattern ==========*/
function Beverage(name, temperature) {
this.name = name;
this.temperature = temperature;
}
Beverage.prototype.drink = function() {
console.log("I'm drinking " + this.name);
};
function Coffee(type) {
Beverage.call(this, "coffee", "hot");
this.type = type;
}
Coffee.prototype = Object.create(Beverage.prototype);
Coffee.prototype.sip = function() {
console.log("Sipping some awesome " + this.type + " " + this.name);
};
var water = new Beverage("water", "cold");
var coffee = new Coffee("bold dark roast");
/*========== Mixins ==========*/
function extend(target) {
if (!arguments[1]) {
return;
}
for (var ii = 1, ll = arguments.length; ii < ll; ii++) {
var source = arguments[ii];
for (var prop in source) {
if (!target[prop] && source.hasOwnProperty(prop)) {
target[prop] = source[prop];
}
}
}
}
function Person(name) {
this.name = name;
}
function Dog(name) {
this.name = name;
}
var speaker = {
speak: function() {
return this.name + " is speaking.";
}
};
var mover = {
walk: function() {
return this.name + " is walking.";
},
run: function() {
return this.name + " is running.";
}
};
var arithmetic = {
add: function() {
return this.name + " is adding numbers together.";
},
multiply: function() {
return this.name + " is multiplying numbers together.";
}
};
//$.extend(Person.prototype, speaker, mover, arithmetic);
//$.extend(Dog.prototype, speaker, mover);
extend(Person.prototype, speaker, mover, arithmetic);
extend(Dog.prototype, speaker, mover);
var john = new Person("John Doe");
var fido = new Dog("Fido");
/*========== Mixins #2 ==========*/
var toolbar = new Toolbar("myToolbar");
var toggle = document.getElementById("itemStateToggle");
toggle.addEventListener("click", function(e) {
e.target.toggleActiveState();
e.preventDefault();
});
function mixin(target, source, methods) {
for (var ii = 2, ll = arguments.length; ii < ll; ii++) {
var method = arguments[ii];
target[method] = source[method].bind(source);
}
}
mixin(toggle, toolbar.items[0], "toggleActiveState");
/*========== Decorator Simple ==========*/
function Coffee() {
}
Coffee.prototype.cost = function() {
return 5;
};
Coffee.small = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost - 1;
};
};
Coffee.medium = function(coffeeObj) {};
Coffee.large = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost + 1;
};
};
Coffee.sugar = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost + .15;
};
};
Coffee.creamer = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost + .15;
};
};
Coffee.whippedCream = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost + .15;
};
};
Coffee.milk = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost + .15;
};
};
Coffee.foam = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost + .15;
};
};
Coffee.chocolate = function(coffeeObj) {
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost + .15;
};
};
Coffee.mocha = function(coffeeObj) {
Coffee.milk(coffeeObj);
Coffee.foam(coffeeObj);
Coffee.chocolate(coffeeObj);
var cost = coffeeObj.cost();
coffeeObj.cost = function() {
return cost;
};
};
var coffee = new Coffee();
var mocha = new Coffee();
/*========== Decorator Prototypal ==========*/
function Beverage() {
this._cost = 0;
}
Beverage.prototype.cost = function() {
return this._cost;
};
function BeverageDecorator(beverage) {
Beverage.call(this);
this.beverage = beverage;
}
BeverageDecorator.prototype = Object.create(Beverage.prototype);
BeverageDecorator.prototype.cost = function() {
return this._cost + this.beverage.cost();
};
function Small(beverage) {
BeverageDecorator.call(this, beverage);
this._cost = -1;
}
Small.prototype = Object.create(BeverageDecorator.prototype);
function Sugar(beverage) {
BeverageDecorator.call(this, beverage);
this._cost = .15;
}
Sugar.prototype = Object.create(BeverageDecorator.prototype);
function Coffee() {
Beverage.call(this);
this._cost = 5;
}
Coffee.prototype = Object.create(Beverage.prototype);
var coffee = new Coffee();
coffee = new Small(coffee);
coffee = new Sugar(coffee);
/*========== Module Pattern ==========*/
var dom = (function(jq) {
var _counter = 0;
function generateId() {
return "customId" + _counter++;
}
function create(tagName, id) {
var el = document.createElement(tagName);
el.id = id || generateId();
return el;
}
return {
generateId: generateId,
create: create
};
}(jQuery));
/*========== Singleton ==========*/
var dom = (function() {
var _counter = 0;
var instance;
function generateId() {
return "customId" + _counter++;
}
function create(tagName, id) {
var el = document.createElement(tagName);
el.id = id || generateId();
return el;
}
function createInstance() {
return {
generateId: generateId,
create: create
};
}
return {
getInstance: function() {
return instance || (instance = createInstance());
}
};
}());
/*========== The Factory ==========*/
define(["lesson09_module"], function(dom) {
function createInput(type) {
var el = dom.create("input");
el.type = type;
return el;
}
var controls = {
text: function(options) {
var el = createInput("text");
if (typeof options.value !== "undefined") {
el.value = options.value;
}
return el;
},
checkbox: function(options) {
var el = createInput("checkbox");
if (typeof options.checked !== "undefined") {
el.checked = options.checked;
}
return el;
}
};
return {
create: function(options) {
var type = options.type ? options.type.toLowerCase() : undefined;
if (!type || !controls[type]) {
throw new {
message: type + " is not supported."
};
}
return controls[type](options);
}
};
});
/*========== The Command Pattern ==========*/
function Calculator() {
this._currentValue = 0;
this.commands = [];
}
Calculator.prototype = {
execute: function(command) {
this._currentValue = command.execute(this._currentValue);
this.commands.push(command);
},
undo: function() {
var cmd = this.commands.pop();
this._currentValue = cmd.undo(this._currentValue);
},
getCurrentValue: function() {
return this._currentValue;
}
};
function add(value) {
return value + this.value;
}
function sub(value) {
return value - this.value;
}
function Command(fn, undo, value) {
this.execute = fn;
this.value = value;
this.undo = undo;
}
function AddCommand(value) {
Command.call(this, add, sub, value);
}
function SubCommand(value) {
Command.call(this, sub, add, value);
}
var calc = new Calculator();
/*========== The Facade Pattern ==========*/
function addEvent(el, ev, fn) {
if (el.addEventListener) {
el.addEventListener(ev, fn, false);
} else if (el.attachEvent) {
el.attachEvent("on" + ev, fn);
} else {
el["on" + ev] = fn;
}
}
function removeEvent(el, ev, fn) {
if (el.removeEventListener) {
el.removeEventListener(ev, fn, false);
} else if (el.detachEvent) {
el.detachEvent("on" + ev, fn);
} else {
el["on" + ev] = null;
}
}
/*========== The Observer Pattern ==========*/
define(function() {
var subscribers = {};
function subscribe(type, fn) {
if (!subscribers[type]) {
subscribers[type] = [];
}
if (subscribers[type].indexOf(fn) == -1) {
subscribers[type].push(fn);
}
}
function unsubscribe(type, fn) {
var listeners = subscribers[type];
if (!listeners) {
return;
}
var index = listeners.indexOf(fn);
if (index > -1) {
listeners.splice(index, 1);
}
}
function publish(type, evtObj) {
if (!subscribers[type]) {
return;
}
if (!evtObj.type) {
evtObj.type = type;
}
var listeners = subscribers[type];
for (var ii = 0, ll = listeners.length; ii < ll; ii++) {
listeners[ii](evtObj);
}
}
return {
subscribe: subscribe,
unsubscribe: unsubscribe,
publish: publish
};
});
/*----- End of DESIGN PATTERNS ------*/