Skip to content

Commit fb53d36

Browse files
author
Badacadabra
committed
Add Iterator (ES5 + ES6 + CoffeeScript + TypeScript)
1 parent ff5caf0 commit fb53d36

File tree

7 files changed

+337
-0
lines changed

7 files changed

+337
-0
lines changed
1.99 KB
Binary file not shown.
15.2 KB
Loading

doc/GoF/Behavioral/Iterator/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Synopsis
2+
3+
I am at the library and I would like to see the list of all available books.
4+
5+
# Problem
6+
7+
There is generally a huge amount of books in a library, so it is great to have a catalog that allows you to have a quick overview of all available references. This catalog may be a bit special and could contain a one-page presentation for each book.
8+
9+
In Javascript, we could use a simple loop to get the list of all books. But in fact, this would not be so convenient because each data structure and entity may have its own particularities when it comes to iteration. For instance, we know we cannot iterate through an array literal like we iterate through an object literal (array-like objects could be considered as an exception). Therefore this is generally a good idea to simplify the work to iterate through a collection...
10+
11+
# Solution
12+
13+
Iterator is the design pattern we need for this. To implement this pattern, we could have:
14+
15+
* An abstract representation of a collection (abstract class or interface)
16+
* An abstract representation of a catalog (abstract class or interface)
17+
* A concrete collection like a library (which is a collection of books)
18+
* A concrete catalog like a library catalog (which references all books)
19+
20+
In this particular case, a collection is an iterable object whereas a catalog is an iterator object.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# ==============================
2+
# ABSTRACT ITERATOR
3+
# ==============================
4+
5+
class Catalog
6+
constructor: ->
7+
throw new Error "You cannot instantiate an abstract class!" if @constructor is Catalog
8+
9+
hasNext: ->
10+
throw new Error "You cannot call an abstract method!"
11+
12+
next: ->
13+
throw new Error "You cannot call an abstract method!"
14+
15+
# ==============================
16+
# ABSTRACT ITERABLE
17+
# ==============================
18+
19+
class Collection
20+
constructor: ->
21+
throw new Error "You cannot instantiate an abstract class!" if @constructor is Collection
22+
23+
list: ->
24+
throw new Error "You cannot call an abstract method!"
25+
26+
# ==============================
27+
# CONCRETE ITERATOR
28+
# ==============================
29+
30+
class LibraryCatalog extends Catalog
31+
constructor: (@_collection) ->
32+
@_index = 0
33+
34+
hasNext: ->
35+
@_index < @_collection.getBooks().length
36+
37+
next: ->
38+
@_collection.getBooks()[@_index++]
39+
40+
# ==============================
41+
# CONCRETE ITERABLE
42+
# ==============================
43+
44+
class Library extends Collection
45+
constructor: (@_books) ->
46+
47+
list: ->
48+
new LibraryCatalog(@)
49+
50+
getBooks: ->
51+
@_books
52+
53+
# ==============================
54+
# CLIENT CODE
55+
# ==============================
56+
57+
# We get the iterator (catalog) from the iterable object (library)
58+
library = new Library ["Foo", "Bar"]
59+
catalog = library.list()
60+
61+
console.log catalog.next() while catalog.hasNext()
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// ==============================
2+
// ABSTRACT ITERATOR
3+
// ==============================
4+
5+
interface Catalog {
6+
hasNext(): boolean;
7+
next(): string;
8+
}
9+
10+
// ==============================
11+
// ABSTRACT ITERABLE
12+
// ==============================
13+
14+
interface Collection {
15+
list(): Catalog;
16+
}
17+
18+
// ==============================
19+
// CONCRETE ITERATOR
20+
// ==============================
21+
22+
class LibraryCatalog implements Catalog {
23+
private index: number = 0;
24+
private collection: Library;
25+
26+
constructor(collection: Library) {
27+
this.collection = collection;
28+
}
29+
30+
hasNext(): boolean {
31+
return this.index < this.collection.getBooks().length;
32+
}
33+
34+
next(): string {
35+
return this.collection.getBooks()[this.index++];
36+
}
37+
}
38+
39+
// ==============================
40+
// CONCRETE ITERABLE
41+
// ==============================
42+
43+
class Library implements Collection {
44+
private books: string[];
45+
46+
constructor(books: string[]) {
47+
this.books = books;
48+
}
49+
50+
public list(): LibraryCatalog {
51+
return new LibraryCatalog(this);
52+
}
53+
54+
public getBooks(): string[] {
55+
return this.books;
56+
}
57+
}
58+
59+
// ==============================
60+
// CLIENT CODE
61+
// ==============================
62+
63+
// We get the iterator (catalog) from the iterable object (library)
64+
let library: Library = new Library(["Foo", "Bar"]),
65+
catalog: LibraryCatalog = library.list();
66+
67+
while (catalog.hasNext()) {
68+
console.log(catalog.next());
69+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
'use strict';
2+
3+
// ==============================
4+
// ABSTRACT ITERATOR
5+
// ==============================
6+
7+
var Catalog = (function () {
8+
function Catalog() {
9+
if (this.constructor === Catalog) {
10+
throw new Error("You cannot instantiate an abstract class!");
11+
}
12+
}
13+
14+
Catalog.prototype.hasNext = function () {
15+
throw new Error("You cannot call an abstract method!");
16+
};
17+
18+
Catalog.prototype.next = function () {
19+
throw new Error("You cannot call an abstract method!");
20+
};
21+
22+
return Catalog;
23+
})();
24+
25+
// ==============================
26+
// ABSTRACT ITERABLE
27+
// ==============================
28+
29+
var Collection = (function () {
30+
function Collection() {
31+
if (this.constructor === Collection) {
32+
throw new Error("You cannot instantiate an abstract class!");
33+
}
34+
}
35+
36+
Collection.prototype.list = function() {
37+
throw new Error("You cannot call an abstract method!");
38+
};
39+
40+
return Collection;
41+
})();
42+
43+
// ==============================
44+
// CONCRETE ITERATOR
45+
// ==============================
46+
47+
var LibraryCatalog = (function () {
48+
var index = 0;
49+
50+
function LibraryCatalog(collection) {
51+
this._collection = collection;
52+
}
53+
LibraryCatalog.prototype = Object.create(Catalog.prototype);
54+
LibraryCatalog.prototype.constructor = LibraryCatalog;
55+
56+
LibraryCatalog.prototype.hasNext = function () {
57+
return index < this._collection.getBooks().length;
58+
};
59+
60+
LibraryCatalog.prototype.next = function () {
61+
return this._collection.getBooks()[index++];
62+
};
63+
64+
return LibraryCatalog;
65+
})();
66+
67+
// ==============================
68+
// CONCRETE ITERABLE
69+
// ==============================
70+
71+
var Library = (function () {
72+
var books = [];
73+
74+
function Library(refs) {
75+
books = refs;
76+
}
77+
Library.prototype = Object.create(Collection.prototype);
78+
Library.prototype.constructor = Library;
79+
80+
Library.prototype.list = function () {
81+
return new LibraryCatalog(this);
82+
};
83+
84+
Library.prototype.getBooks = function () {
85+
return books;
86+
};
87+
88+
return Library;
89+
})();
90+
91+
// ==============================
92+
// CLIENT CODE
93+
// ==============================
94+
95+
// We get the iterator (catalog) from the iterable object (library)
96+
var library = new Library(["Foo", "Bar"]),
97+
catalog = library.list();
98+
99+
while (catalog.hasNext()) {
100+
console.log(catalog.next());
101+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// ==============================
2+
// ABSTRACT ITERATOR
3+
// ==============================
4+
5+
class Catalog {
6+
constructor() {
7+
if (new.target !== undefined) {
8+
throw new Error("You cannot instantiate an abstract class!");
9+
}
10+
}
11+
12+
hasNext() {
13+
throw new Error("You cannot call an abstract method!");
14+
}
15+
16+
next() {
17+
throw new Error("You cannot call an abstract method!");
18+
}
19+
}
20+
21+
// ==============================
22+
// ABSTRACT ITERABLE
23+
// ==============================
24+
25+
class Collection {
26+
constructor() {
27+
if (new.target !== undefined) {
28+
throw new Error("You cannot instantiate an abstract class!");
29+
}
30+
}
31+
32+
list() {
33+
throw new Error("You cannot call an abstract method!");
34+
}
35+
}
36+
37+
// ==============================
38+
// CONCRETE ITERATOR
39+
// ==============================
40+
41+
class LibraryCatalog extends Catalog {
42+
constructor(collection) {
43+
super();
44+
this._index = 0;
45+
this._collection = collection;
46+
}
47+
48+
hasNext() {
49+
return this._index < this._collection.books.length;
50+
}
51+
52+
next() {
53+
return this._collection.books[this._index++];
54+
}
55+
}
56+
57+
// ==============================
58+
// CONCRETE ITERABLE
59+
// ==============================
60+
61+
class Library extends Collection {
62+
constructor(books) {
63+
super();
64+
this._books = books;
65+
}
66+
67+
list() {
68+
return new LibraryCatalog(this);
69+
}
70+
71+
get books() {
72+
return this._books;
73+
}
74+
}
75+
76+
// ==============================
77+
// CLIENT CODE
78+
// ==============================
79+
80+
// We get the iterator (catalog) from the iterable object (library)
81+
let library = new Library(["Foo", "Bar"]),
82+
catalog = library.list();
83+
84+
while (catalog.hasNext()) {
85+
console.log(catalog.next());
86+
}

0 commit comments

Comments
 (0)