Skip to content

Commit 4749af5

Browse files
author
Badacadabra
committed
Add Strategy (ES5 + ES6 + CoffeeScript + TypeScript)
1 parent e73f3aa commit 4749af5

File tree

7 files changed

+259
-0
lines changed

7 files changed

+259
-0
lines changed

doc/GoF/Behavioral/Strategy/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Synopsis
2+
3+
I am playing a fighting game and I do not know my opponent. Should I prefer an offensive or defensive style?
4+
5+
# Problem
6+
7+
Since the opponent is unknown, the player has to choose a fighting strategy on the fly.
8+
In programming terms, we can say that an algorithm has to be selected at runtime, among several available algorithms.
9+
10+
# Solution
11+
12+
The Strategy design pattern is exactly what we need in this kind of situation. To implement this pattern, we can have:
13+
14+
* A concrete context (FightingGame) which contains a reference to a strategy
15+
* An abstract representation of a strategy (abstract class or interface)
16+
* Concrete strategies (Offense & Defense)
2.12 KB
Binary file not shown.
16.2 KB
Loading
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# ==============================
2+
# CONCRETE CONTEXT
3+
# ==============================
4+
5+
class FightingGame
6+
constructor: ->
7+
@_strategy = null
8+
9+
play: ->
10+
@_strategy.fight()
11+
12+
setStrategy: (fightStyle) ->
13+
@_strategy = fightStyle
14+
15+
# ==============================
16+
# ABSTRACT STRATEGY
17+
# ==============================
18+
19+
class Strategy
20+
constructor: ->
21+
throw new Error "You cannot instantiate an abstract class!" if @constructor is Strategy
22+
23+
fight: ->
24+
throw new Error "You cannot call an abstract method!"
25+
26+
# ==============================
27+
# CONCRETE STRATEGIES
28+
# ==============================
29+
30+
class Offense extends Strategy
31+
fight: ->
32+
"Fight with an offensive style"
33+
34+
class Defense extends Strategy
35+
fight: ->
36+
"Fight with a defensive style"
37+
38+
# ==============================
39+
# CLIENT CODE
40+
# ==============================
41+
42+
game = new FightingGame
43+
offense = new Offense
44+
defense = new Defense
45+
46+
game.setStrategy defense
47+
console.log "ROUND 1 - #{game.play()}"
48+
game.setStrategy offense
49+
console.log "ROUND 2 - #{game.play()}"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// ==============================
2+
// CONCRETE CONTEXT
3+
// ==============================
4+
5+
class FightingGame {
6+
private strategy: Strategy;
7+
8+
play(): string {
9+
return this.strategy.fight();
10+
}
11+
12+
setStrategy(fightStyle: Strategy): void {
13+
this.strategy = fightStyle;
14+
}
15+
}
16+
17+
// ==============================
18+
// ABSTRACT STRATEGY
19+
// ==============================
20+
21+
interface Strategy {
22+
fight(): string;
23+
}
24+
25+
// ==============================
26+
// CONCRETE STRATEGIES
27+
// ==============================
28+
29+
class Offense implements Strategy {
30+
fight(): string {
31+
return "Fight with an offensive style";
32+
}
33+
}
34+
35+
class Defense implements Strategy {
36+
fight(): string {
37+
return "Fight with a defensive style";
38+
}
39+
}
40+
41+
// ==============================
42+
// CLIENT CODE
43+
// ==============================
44+
45+
let game: FightingGame = new FightingGame(),
46+
offense: Strategy = new Offense(),
47+
defense: Strategy = new Defense();
48+
49+
game.setStrategy(defense);
50+
console.log(`ROUND 1 - ${game.play()}`);
51+
game.setStrategy(offense);
52+
console.log(`ROUND 2 - ${game.play()}`);
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
'use strict';
2+
3+
// ==============================
4+
// CONCRETE CONTEXT
5+
// ==============================
6+
7+
var FightingGame = (function () {
8+
var strategy = null;
9+
10+
function FightingGame() {}
11+
12+
FightingGame.prototype.play = function () {
13+
return strategy.fight();
14+
};
15+
16+
FightingGame.prototype.setStrategy = function (fightStyle) {
17+
strategy = fightStyle;
18+
};
19+
20+
return FightingGame;
21+
})();
22+
23+
// ==============================
24+
// ABSTRACT STRATEGY
25+
// ==============================
26+
27+
var Strategy = (function() {
28+
function Strategy() {
29+
if (this.constructor === Strategy) {
30+
throw new Error("You cannot instantiate an abstract class!");
31+
}
32+
}
33+
34+
Strategy.prototype.fight = function () {
35+
throw new Error("You cannot call an abstract method!");
36+
};
37+
38+
return Strategy;
39+
})();
40+
41+
// ==============================
42+
// CONCRETE STRATEGIES
43+
// ==============================
44+
45+
var Offense = (function () {
46+
function Offense() {}
47+
Offense.prototype = Object.create(Strategy.prototype);
48+
Offense.prototype.constructor = Offense;
49+
50+
Offense.prototype.fight = function () {
51+
return "Fight with an offensive style";
52+
};
53+
54+
return Offense;
55+
})();
56+
57+
var Defense = (function () {
58+
function Defense() {}
59+
Defense.prototype = Object.create(Strategy.prototype);
60+
Defense.prototype.constructor = Defense;
61+
62+
Defense.prototype.fight = function () {
63+
return "Fight with a defensive style";
64+
};
65+
66+
return Defense;
67+
})();
68+
69+
// ==============================
70+
// CLIENT CODE
71+
// ==============================
72+
73+
var game = new FightingGame(),
74+
offense = new Offense(),
75+
defense = new Defense();
76+
77+
game.setStrategy(defense);
78+
console.log("ROUND 1 - " + game.play());
79+
game.setStrategy(offense);
80+
console.log("ROUND 2 - " + game.play());
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// ==============================
2+
// CONCRETE CONTEXT
3+
// ==============================
4+
5+
class FightingGame {
6+
constructor() {
7+
this._strategy = null;
8+
}
9+
10+
play() {
11+
return this._strategy.fight();
12+
}
13+
14+
setStrategy(fightStyle) {
15+
this._strategy = fightStyle;
16+
}
17+
}
18+
19+
// ==============================
20+
// ABSTRACT STRATEGY
21+
// ==============================
22+
23+
class Strategy {
24+
constructor() {
25+
if (new.target !== undefined) {
26+
throw new Error("You cannot instantiate an abstract class!");
27+
}
28+
}
29+
30+
fight() {
31+
throw new Error("You cannot call an abstract method!");
32+
}
33+
}
34+
35+
// ==============================
36+
// CONCRETE STRATEGIES
37+
// ==============================
38+
39+
class Offense extends Strategy {
40+
fight() {
41+
return "Fight with an offensive style";
42+
}
43+
}
44+
45+
class Defense extends Strategy {
46+
fight() {
47+
return "Fight with a defensive style";
48+
}
49+
}
50+
51+
// ==============================
52+
// CLIENT CODE
53+
// ==============================
54+
55+
let game = new FightingGame(),
56+
offense = new Offense(),
57+
defense = new Defense();
58+
59+
game.setStrategy(defense);
60+
console.log(`ROUND 1 - ${game.play()}`);
61+
game.setStrategy(offense);
62+
console.log(`ROUND 2 - ${game.play()}`);

0 commit comments

Comments
 (0)