Skip to content
This repository was archived by the owner on Mar 1, 2021. It is now read-only.

Commit 4d6294a

Browse files
committed
Add source for decorator, iterator and observer
Update README
1 parent 23f681f commit 4d6294a

File tree

12 files changed

+319
-6
lines changed

12 files changed

+319
-6
lines changed

Diff for: README.md

+11-5
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
- Factory Method
88
- Object Pool
99
- Prototype
10-
- Singleton
10+
- [Singleton](http://robdodson.me/blog/2012/08/08/javascript-design-patterns-singleton/)
1111

1212
## Structural
1313

1414
- Adapter
1515
- Bridge
1616
- Composite
17-
- Decorator
17+
- [Decorator](http://robdodson.me/blog/2012/08/27/javascript-design-patterns-decorator/)
1818
- Facade
1919
- Flyweight
2020
- Private Class Data
@@ -25,15 +25,21 @@
2525
- Chain of Responsibility
2626
- Command
2727
- Interpreter
28-
- Iterator
28+
- [Iterator](http://robdodson.me/blog/2012/08/10/javascript-design-patterns-iterator/)
2929
- Mediator
3030
- Memento
3131
- Null Object
32-
- Observer
32+
- [Observer](http://robdodson.me/blog/2012/08/16/javascript-design-patterns-observer/)
3333
- State
34-
- Strategy
34+
- [Strategy](http://robdodson.me/blog/2012/08/03/javascript-design-patterns-strategy/)
3535
- Template Method
3636
- Visitor
3737
- Monad Pattern / Promises
3838

39+
It occurred to me that I’ve always wanted to go through the Gang of Four book and just write my own interpretation of each pattern. Since I’m currently working primarily in JavaScript I thought it might be an interesting challenge to convert their examples, often in strongly typed languages, to something as dynamic and loosey-goosey as JS.
40+
41+
I know there are a lot of people out there who aren’t too keen on design patterns but that’s not to say that they shouldn’t be used or studied. There’s a lot of code out there that starts with jQuery.click() or addEventListener or .on() and all of them are implementations of the Observer pattern. Finding this reusable approach is the main point of patterns and along with it comes a shared vocabulary that can be passed on to other developers. Rather than saying “Let’s defer the methods of our object that are subject to change to well encapsulated algorithms.” We can just say “A Strategy pattern might be nice here.”
42+
43+
Patterns should be used with caution as not everything fits so neatly into their paradigms. It’s often said that a beginner never met a pattern he didn’t like. In my experiences I’ve been burned by pattern overuse and at other times they have legitimately saved my ass. It’s also true that many patterns don’t really work or aren’t appropriate for particular languages. For instance, the GoF book was written primarily for languages which shared features of C++ and SmallTalk. I totally agree with this sentiment but I feel like along the way we’ll discover what does and doesn’t make sense in a dynamic language like JS and hopefully we can toss in some new patterns of our own. Already to the list I’ve added Promises which I use quite frequently and find to be a wonderful alternative to JavaScript’s oft seen pyramid of callbacks. Again, this is all about learning and experimenting. In my opinion a good understanding of design patterns is a threshold that needs to be crossed at some point in your career. I’m committed to doing this twice a week for the next several weeks so hopefully by the end of it we’ll have a useful resource that others can benefit from. Stay tuned!
44+
3945
[http://robdodson.me/blog/2012/08/03/javascript-design-patterns/](http://robdodson.me/blog/2012/08/03/javascript-design-patterns/)

Diff for: decorator/sale/index.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Decorators: The Hard Way</title>
6+
<meta name="description" content="">
7+
<meta name="author" content="">
8+
</head>
9+
<body>
10+
<script type="text/javascript" src="main.js"></script>
11+
</body>
12+
</html>

Diff for: decorator/sale/main.js

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Full credit for this example goes to Stoyan Stefanov and his
2+
// amazing book JavaScript Patterns
3+
// http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
4+
5+
"use strict";
6+
7+
function Sale(price) {
8+
this.price = price || 100;
9+
}
10+
11+
Sale.prototype.getPrice = function() {
12+
return this.price;
13+
};
14+
15+
Sale.decorators = {};
16+
17+
Sale.decorators.fedtax = {
18+
getPrice: function() {
19+
var price = this._super.getPrice();
20+
price += price * 5 / 100;
21+
return price;
22+
}
23+
};
24+
25+
Sale.decorators.quebec = {
26+
getPrice: function() {
27+
var price = this._super.getPrice();
28+
price += price * 7.5 / 100;
29+
return price;
30+
}
31+
};
32+
33+
Sale.decorators.money = {
34+
getPrice: function() {
35+
return "$" + this._super.getPrice().toFixed(2);
36+
}
37+
};
38+
39+
Sale.decorators.cdn = {
40+
getPrice: function() {
41+
return "CDN$" + this._super.getPrice().toFixed(2);
42+
}
43+
};
44+
45+
Sale.prototype.decorate = function (decorator) {
46+
var F = function () {},
47+
overrides = this.constructor.decorators[decorator],
48+
i,
49+
newobj;
50+
51+
// Create prototype chain
52+
F.prototype = this;
53+
newobj = new F();
54+
newobj._super = F.prototype;
55+
56+
// Mixin properties/methods of our decorator
57+
// Overriding the ones from our prototype
58+
for (i in overrides) {
59+
if (overrides.hasOwnProperty(i)) {
60+
newobj[i] = overrides[i];
61+
}
62+
}
63+
64+
return newobj;
65+
};
66+
67+
var sale = new Sale(50);
68+
sale = sale.decorate('fedtax');
69+
sale = sale.decorate('cdn');
70+
console.log(sale.getPrice());

Diff for: decorator/validator/index.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Decorators: The Easy Way</title>
6+
<meta name="description" content="">
7+
<meta name="author" content="">
8+
</head>
9+
<body>
10+
<script type="text/javascript" src="main.js"></script>
11+
</body>
12+
</html>

Diff for: decorator/validator/main.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"use strict";
2+
3+
function Validator () {
4+
this.errors = [];
5+
this.decoratorsList = [];
6+
}
7+
8+
Validator.prototype.decorate = function(name, args) {
9+
this.decoratorsList.push({ name: name, args: args });
10+
};
11+
12+
Validator.decorators = {};
13+
14+
Validator.decorators.hasName = {
15+
validate: function(form, args) {
16+
// Code to verify presence of name...
17+
18+
this.errors.push('no name!');
19+
}
20+
};
21+
22+
Validator.decorators.hasAge = {
23+
validate: function(form, args) {
24+
// Code to verify presence of age...
25+
26+
this.errors.push('no age!');
27+
}
28+
};
29+
30+
Validator.decorators.hasZipCode = {
31+
validate: function(form, args) {
32+
// Code to verify presence of zip code...
33+
34+
this.errors.push('no zip!');
35+
}
36+
};
37+
38+
Validator.prototype.validate = function(form) {
39+
var i,
40+
max,
41+
temp,
42+
name,
43+
args;
44+
45+
this.form = form;
46+
47+
max = this.decoratorsList.length;
48+
for (i = 0; i < max; i++) {
49+
temp = this.decoratorsList[i];
50+
name = temp.name;
51+
args = temp.args;
52+
Validator.decorators[name].validate.call(this, form, args);
53+
}
54+
};
55+
56+
// Try it out!
57+
var validator = new Validator();
58+
validator.decorate('hasName', { length: 5 });
59+
validator.decorate('hasAge', { minimum: 21 });
60+
validator.decorate('hasZipCode');
61+
validator.validate({}); // some form data. in this case just an anonymous object
62+
console.log(validator.errors);
63+
64+
65+

Diff for: iterator/arrays/index.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Iterator: Arrays</title>
6+
<meta name="description" content="">
7+
<meta name="author" content="">
8+
</head>
9+
<body>
10+
<script type="text/javascript" src="main.js"></script>
11+
</body>
12+
</html>

Diff for: iterator/arrays/main.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Examples inspired by Stoyan Stefanov and his
2+
// amazing book JavaScript Patterns
3+
// http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
4+
5+
"use strict";
6+
7+
var iterator = (function() {
8+
9+
var index = 0,
10+
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
11+
length = data.length;
12+
13+
return {
14+
next: function() {
15+
var element;
16+
if (!this.hasNext()) {
17+
return null;
18+
}
19+
element = data[index];
20+
index += 3;
21+
return element;
22+
},
23+
hasNext: function() {
24+
return index < length;
25+
},
26+
rewind: function() {
27+
index = 0;
28+
return data[index];
29+
},
30+
current: function() {
31+
return data[index];
32+
}
33+
};
34+
35+
}());

Diff for: iterator/objects/index.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Iterator: Objects</title>
6+
<meta name="description" content="">
7+
<meta name="author" content="">
8+
</head>
9+
<body>
10+
<script type="text/javascript" src="main.js"></script>
11+
</body>
12+
</html>

Diff for: iterator/objects/main.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Examples inspired by Stoyan Stefanov and his
2+
// amazing book JavaScript Patterns
3+
// http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
4+
5+
"use strict";
6+
7+
var iterator = (function() {
8+
var data = { foo: 'foo', bar: 'bar', baz: 'baz' },
9+
keys = Object.keys(data),
10+
index = 0,
11+
length = keys.length;
12+
13+
return {
14+
next: function() {
15+
var element;
16+
if (!this.hasNext()) {
17+
return null;
18+
}
19+
element = data[keys[index]];
20+
index++;
21+
return element;
22+
},
23+
hasNext: function() {
24+
return index < length;
25+
},
26+
rewind: function() {
27+
index = 0;
28+
return data[keys[index]];
29+
},
30+
current: function() {
31+
return data[keys[index]];
32+
}
33+
};
34+
35+
}());

Diff for: observer/publisher/index.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Observer: Publisher</title>
6+
<meta name="description" content="">
7+
<meta name="author" content="">
8+
</head>
9+
<body>
10+
<script type="text/javascript" src="main.js"></script>
11+
</body>
12+
</html>

Diff for: observer/publisher/main.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Full credit for this example goes to Stoyan Stefanov and his
2+
// amazing book JavaScript Patterns
3+
// http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
4+
5+
"use strict";
6+
7+
var publisher = {
8+
subscribers: {
9+
any: [] // event type: subscribers
10+
},
11+
on: function(type, fn, context) {
12+
type = type || 'any';
13+
fn = typeof fn === 'function' ? fn : context[fn];
14+
if (typeof this.subscribers[type] === "undefined") {
15+
this.subscribers[type] = [];
16+
}
17+
this.subscribers[type].push({ fn: fn, context: context || this });
18+
},
19+
remove: function(type, fn, context) {
20+
this.visitSubscribers('unsubscribe', type, fn, context);
21+
},
22+
fire: function(type, publication) {
23+
this.visitSubscribers('publish', type, publication);
24+
},
25+
visitSubscribers: function(action, type, arg, context) {
26+
var pubtype = type || 'any',
27+
subscribers = this.subscribers[pubtype],
28+
i,
29+
max = subscribers ? subscribers.length : 0;
30+
31+
for (i = 0; i < max; i += 1) {
32+
if (action === 'publish') {
33+
// Call our observers, passing along arguments
34+
 subscribers[i].fn.call(subscribers[i].context, arg);
35+
} else {
36+
if (subscribers[i].fn === arg && subscribers[i].context === context) {
37+
subscribers.splice(i, 1);
38+
}
39+
}
40+
}
41+
}
42+
};

Diff for: strategy/painter/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html lang="en">
33
<head>
44
<meta charset="utf-8">
5-
<title>Painter</title>
5+
<title>Strategy: Painter</title>
66
<meta name="description" content="Strategy pattern in JavaScript with pretty pictures!">
77
<meta name="author" content="Rob Dodson">
88
<style type="text/css">

0 commit comments

Comments
 (0)