Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 11ae76d

Browse files
author
Badacadabra
committed
Add Flyweight (ES5 + ES6 + CoffeeScript)
1 parent 1752dcb commit 11ae76d

File tree

6 files changed

+288
-0
lines changed

6 files changed

+288
-0
lines changed
2.32 KB
Binary file not shown.
20.8 KB
Loading[フレーム]

‎doc/GoF/Structural/Flyweight/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Synopsis
2+
3+
I am a fan of GNU/Linux distributions and I want to test the big names: Debian, RedHat, Slackware. However, I am too busy to test all versions available. The latest version of each distro would be just fine.
4+
5+
# Problem
6+
7+
Everytime we use "new", we create a new object in JavaScript. But if we know the instance we need will always be the same (e.g. a very specific version of Debian), this is not optimal to create multiple instances that represent the same thing. Each instantiation operation has a cost in terms of performance and memory which should be minimized as much as possible.
8+
9+
# Solution
10+
11+
We can use Flyweight here, which is actually tied to Factory. A Factory handles flyweights when it reuses instances instead of constantly creating new ones. Here we have:
12+
13+
* An abstract representation of a Linux distro (abstract class or interface)
14+
* Concrete implementations of this abstraction (Debian, RedHat, Slackware)
15+
* A "class" with a factory method which will be responsible for instantiation (contrary to a simple Factory method, some extra code is required to test if the wanted instance already exists or not)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"use strict"
2+
3+
# ==============================
4+
# ABSTRACT GNU/LINUX DISTRO
5+
# ==============================
6+
7+
class LinuxDistro
8+
constructor: (name) ->
9+
throw new Error "You cannot instantiate an abstract class!" if @constructor is LinuxDistro
10+
@name = name
11+
12+
boot: ->
13+
"#{@name} is booting..." # string interpolation with template literal
14+
15+
# ==============================
16+
# CONCRETE GNU/LINUX DISTROS
17+
# ==============================
18+
19+
# Let's say that each instance of a Linux distro will have the name of its constructor...
20+
21+
class Debian extends LinuxDistro
22+
constructor: ->
23+
super "Debian"
24+
25+
class RedHat extends LinuxDistro
26+
constructor: ->
27+
super "RedHat"
28+
29+
class Slackware extends LinuxDistro
30+
constructor: ->
31+
super "Slackware"
32+
33+
# ==============================
34+
# FACTORY OF GNU/LINUX DISTROS
35+
# ==============================
36+
37+
class LinuxDistrosFactory
38+
@DEBIAN: 0
39+
@REDHAT: 1
40+
@SLACKWARE: 2
41+
42+
# Flyweights!
43+
@activeDistros: Object.create(null) # new object without prototype, like a basic map
44+
45+
@getLinuxDistro: (id) ->
46+
# If the distro has never been instantiated, we will have to create a new object
47+
unless @activeDistros[id]
48+
switch id
49+
when @DEBIAN then @activeDistros[id] = new Debian()
50+
when @REDHAT then @activeDistros[id] = new RedHat()
51+
when @SLACKWARE then @activeDistros[id] = new Slackware()
52+
else throw new Error "The Linux distribution you are looking for has not been found"
53+
54+
# If the distro has already been instantiated, we return the initial instance
55+
@activeDistros[id];
56+
57+
# ==============================
58+
# CLIENT CODE
59+
# ==============================
60+
61+
# Creation of our objects through the factory
62+
debian = LinuxDistrosFactory.getLinuxDistro LinuxDistrosFactory.DEBIAN
63+
debianAgain = LinuxDistrosFactory.getLinuxDistro LinuxDistrosFactory.DEBIAN
64+
65+
console.log debian.boot() # Debian is booting...
66+
console.log debianAgain.boot() # Debian is booting...
67+
console.log debian is debianAgain # true (the same instance has been reused)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
'use strict';
2+
3+
// ==============================
4+
// ABSTRACT GNU/LINUX DISTRO
5+
// ==============================
6+
7+
var LinuxDistro = (function () {
8+
function LinuxDistro(name) {
9+
if (this.constructor === LinuxDistro) {
10+
throw new Error("You cannot instantiate an abstract class!");
11+
}
12+
this.name = name;
13+
}
14+
15+
LinuxDistro.prototype.boot = function () {
16+
return this.name + " is booting...";
17+
};
18+
19+
return LinuxDistro;
20+
})();
21+
22+
// ==============================
23+
// CONCRETE GNU/LINUX DISTROS
24+
// ==============================
25+
26+
// Let's say that each instance of a Linux distro will have the name of its constructor...
27+
28+
var Debian = (function () {
29+
function Debian() {
30+
LinuxDistro.call(this, "Debian");
31+
}
32+
Debian.prototype = Object.create(LinuxDistro.prototype);
33+
Debian.prototype.constructor = Debian;
34+
35+
return Debian;
36+
})();
37+
38+
var RedHat = (function () {
39+
function RedHat() {
40+
LinuxDistro.call(this, "RedHat");
41+
}
42+
RedHat.prototype = Object.create(LinuxDistro.prototype);
43+
RedHat.prototype.constructor = RedHat;
44+
45+
return RedHat;
46+
})();
47+
48+
var Slackware = (function () {
49+
function Slackware() {
50+
LinuxDistro.call(this, "Slackware");
51+
}
52+
Slackware.prototype = Object.create(LinuxDistro.prototype);
53+
Slackware.prototype.constructor = Slackware;
54+
55+
return Slackware;
56+
})();
57+
58+
// ==============================
59+
// FACTORY OF GNU/LINUX DISTROS
60+
// ==============================
61+
62+
var LinuxDistrosFactory = (function () {
63+
function LinuxDistrosFactory() {}
64+
65+
// The only way to declare real constants in ES5 (non writable and non configurable)
66+
Object.defineProperties(LinuxDistrosFactory, {
67+
"DEBIAN": {
68+
value: 0,
69+
enumerable: true
70+
},
71+
"REDHAT": {
72+
value: 1,
73+
enumerable: true
74+
},
75+
"SLACKWARE": {
76+
value: 2,
77+
enumerable: true
78+
},
79+
"activeDistros": { // Flyweights!
80+
value: Object.create(null), // new object without prototype, like a basic map
81+
enumerable: true
82+
}
83+
});
84+
85+
// Static method to get an instance of the given type
86+
LinuxDistrosFactory.getLinuxDistro = function (id) {
87+
// If the distro has never been instantiated, we will have to create a new object
88+
if (!this.activeDistros[id]) {
89+
switch (id) {
90+
case this.DEBIAN:
91+
this.activeDistros[id] = new Debian();
92+
break;
93+
case this.REDHAT:
94+
this.activeDistros[id] = new RedHat();
95+
break;
96+
case this.SLACKWARE:
97+
this.activeDistros[id] = new Slackware();
98+
break;
99+
default:
100+
throw new Error("The Linux distribution you are looking for has not been found");
101+
}
102+
}
103+
// If the distro has already been instantiated, we return the initial instance
104+
return this.activeDistros[id];
105+
};
106+
107+
return LinuxDistrosFactory;
108+
})();
109+
110+
// ==============================
111+
// CLIENT CODE
112+
// ==============================
113+
114+
// Creation of our objects through the factory
115+
var debian = LinuxDistrosFactory.getLinuxDistro(LinuxDistrosFactory.DEBIAN),
116+
debianAgain = LinuxDistrosFactory.getLinuxDistro(LinuxDistrosFactory.DEBIAN);
117+
118+
console.log(debian.boot()); // Debian is booting...
119+
console.log(debianAgain.boot()); // Debian is booting...
120+
console.log(debian === debianAgain); // true (the same instance has been reused)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// ==============================
2+
// ABSTRACT GNU/LINUX DISTRO
3+
// ==============================
4+
5+
class LinuxDistro {
6+
constructor(name) {
7+
if (new.target !== undefined) {
8+
throw new Error("You cannot instantiate an abstract class!");
9+
}
10+
this._name = name;
11+
}
12+
13+
boot() {
14+
return `${this._name} is booting...`; // string interpolation with template literal
15+
}
16+
}
17+
18+
// ==============================
19+
// CONCRETE GNU/LINUX DISTROS
20+
// ==============================
21+
22+
// Let's say that each instance of a Linux distro will have the name of its constructor...
23+
24+
class Debian extends LinuxDistro {
25+
constructor() {
26+
super(Debian.name);
27+
}
28+
}
29+
30+
class RedHat extends LinuxDistro {
31+
constructor() {
32+
super(RedHat.name);
33+
}
34+
}
35+
36+
class Slackware extends LinuxDistro {
37+
constructor() {
38+
super(Slackware.name);
39+
}
40+
}
41+
42+
// ==============================
43+
// FACTORY OF GNU/LINUX DISTROS
44+
// ==============================
45+
46+
class LinuxDistrosFactory {
47+
// We cannot use "const" inside a class in ES6.
48+
// Only methods are supported.
49+
static get DEBIAN() { return 0; }
50+
static get REDHAT() { return 1; }
51+
static get SLACKWARE() { return 2; }
52+
53+
static getLinuxDistro(id) {
54+
// If the distro has never been instantiated, we will have to create a new object
55+
if (!this.activeDistros.has(id)) {
56+
switch (id) {
57+
case this.DEBIAN:
58+
this.activeDistros.set(id, new Debian());
59+
break;
60+
case this.REDHAT:
61+
this.activeDistros.set(id, new RedHat());
62+
break;
63+
case this.SLACKWARE:
64+
this.activeDistros.set(id, new Slackware());
65+
break;
66+
default:
67+
throw new Error("The Linux distribution you are looking for has not been found");
68+
}
69+
}
70+
// If the distro has already been instantiated, we return the initial instance
71+
return this.activeDistros.get(id);
72+
}
73+
}
74+
LinuxDistrosFactory.activeDistros = new Map(); // Flyweights!
75+
76+
// ==============================
77+
// CLIENT CODE
78+
// ==============================
79+
80+
// Creation of our objects through the factory
81+
let debian = LinuxDistrosFactory.getLinuxDistro(LinuxDistrosFactory.DEBIAN),
82+
debianAgain = LinuxDistrosFactory.getLinuxDistro(LinuxDistrosFactory.DEBIAN);
83+
84+
console.log(debian.boot()); // Debian is booting...
85+
console.log(debianAgain.boot()); // Debian is booting...
86+
console.log(debian === debianAgain); // true (the same instance has been reused)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /