Skip to content

Commit 33929d2

Browse files
author
Badacadabra
committed
Add Command (ES5 + ES6 + CoffeeScript + TypeScript)
1 parent 7d1ad9d commit 33929d2

File tree

7 files changed

+302
-0
lines changed

7 files changed

+302
-0
lines changed
2.14 KB
Binary file not shown.
17.7 KB
Loading

doc/GoF/Behavioral/Command/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Synopsis
2+
3+
I am hungry and I decide to call the nearest Tex-Mex restaurant to place an order. I hope I will receive my meal fast.
4+
5+
# Problem
6+
7+
Placing an order is easy to do. As a customer, you only need to say what you want to eat and nothing else. However, for the restaurant, there is a true organization behind the scenes to effectively treat your order. The chef cooks for you, then the meal is packaged and finally the delivery man brings it to you as fast as possible. Plus, you are not the only one to be hungry... The restaurant is most likely in a situation where it has to handle many orders, especially when it is time for dinner.
8+
9+
In computer science terms, it seems obvious that the restaurant has to handle a queue of orders and that each customer is a unique entity. Since a customer normally pays his order to the delivery man, the payment should be the last step of the process. But this is not so intuitive if you try to find a good code organization for this. On the one hand, all orders are handled by the restaurant and everything required to prepare these orders is like encapsulated in each order. On the other hand, only customers can validate orders since their responsible for payment.
10+
11+
# Solution
12+
13+
The Command pattern is a great help here. In this pattern terminology, we will say that:
14+
***
15+
* The restaurant is the "invoker" who creates and handles new orders internally
16+
* The order is the "command", in other words the request which comes from a client
17+
* The customer is the "receiver" of the order
18+
19+
To implement this pattern, we then need:
20+
21+
* A concrete "class" representing the restaurant
22+
* An abstract representation of an order (abstract class or interface)
23+
* A concrete order that we will call "TexMex" (this one must have a reference to the customer)
24+
* A concrete customer whose action (pay) will be triggered from the order itself
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# ==============================
2+
# ABSTRACT ORDER
3+
# ==============================
4+
5+
class Order
6+
constructor: ->
7+
throw new Error "You cannot instantiate an abstract class!" if @constructor is Order
8+
9+
deliver: ->
10+
throw new Error "You cannot call an abstract method!"
11+
12+
# ==============================
13+
# CONCRETE ORDER
14+
# ==============================
15+
16+
class TexMex extends Order
17+
constructor: (@customer) ->
18+
19+
deliver: ->
20+
@customer.pay()
21+
22+
# ==============================
23+
# CONCRETE RESTAURANT
24+
# ==============================
25+
26+
class Restaurant
27+
constructor: ->
28+
@_orders = []
29+
30+
addOrder: (order) ->
31+
@_orders.push order
32+
33+
prepareOrders: ->
34+
summary = ""
35+
summary += order.deliver() for order in @_orders
36+
summary
37+
38+
# ==============================
39+
# CONCRETE CUSTOMER
40+
# ==============================
41+
42+
class Customer
43+
pay: ->
44+
"Payment OK!\n"
45+
46+
# ==============================
47+
# CLIENT CODE
48+
# ==============================
49+
50+
customer = new Customer
51+
order = new TexMex customer
52+
restaurant = new Restaurant
53+
54+
restaurant.addOrder order
55+
console.log restaurant.prepareOrders()
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// ==============================
2+
// ABSTRACT ORDER
3+
// ==============================
4+
5+
interface Order {
6+
deliver(): string;
7+
}
8+
9+
// ==============================
10+
// CONCRETE ORDER
11+
// ==============================
12+
13+
class TexMex implements Order {
14+
private customer: Customer;
15+
16+
constructor(customer: Customer) {
17+
this.customer = customer;
18+
}
19+
20+
public deliver(): string {
21+
return this.customer.pay();
22+
}
23+
}
24+
25+
// ==============================
26+
// CONCRETE RESTAURANT
27+
// ==============================
28+
29+
class Restaurant {
30+
private orders: Order[] = [];
31+
32+
addOrder(order: Order): void {
33+
this.orders.push(order);
34+
}
35+
36+
prepareOrders(): string {
37+
let summary: string = "";
38+
for (let order of this.orders) {
39+
summary += order.deliver();
40+
}
41+
return summary;
42+
}
43+
}
44+
45+
// ==============================
46+
// CONCRETE CUSTOMER
47+
// ==============================
48+
49+
class Customer {
50+
pay(): string {
51+
return "Payment OK!\n";
52+
}
53+
}
54+
55+
// ==============================
56+
// CLIENT CODE
57+
// ==============================
58+
59+
let customer: Customer = new Customer(),
60+
order: Order = new TexMex(customer),
61+
restaurant: Restaurant = new Restaurant();
62+
63+
restaurant.addOrder(order);
64+
console.log(restaurant.prepareOrders());
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'use strict';
2+
3+
// ==============================
4+
// ABSTRACT ORDER
5+
// ==============================
6+
7+
var Order = (function() {
8+
function Order() {
9+
if (this.constructor === Order) {
10+
throw new Error("You cannot instantiate an abstract class!");
11+
}
12+
}
13+
14+
Order.prototype.deliver = function () {
15+
throw new Error("You cannot call an abstract method!");
16+
};
17+
18+
return Order;
19+
})();
20+
21+
// ==============================
22+
// CONCRETE ORDER
23+
// ==============================
24+
25+
var TexMex = (function () {
26+
function TexMex(customer) {
27+
this.customer = customer;
28+
}
29+
TexMex.prototype = Object.create(Order.prototype);
30+
TexMex.prototype.constructor = TexMex;
31+
32+
TexMex.prototype.deliver = function () {
33+
return this.customer.pay();
34+
};
35+
36+
return TexMex;
37+
})();
38+
39+
// ==============================
40+
// CONCRETE RESTAURANT
41+
// ==============================
42+
43+
var Restaurant = (function () {
44+
var orders = [];
45+
46+
function Restaurant() {}
47+
48+
Restaurant.prototype.addOrder = function (order) {
49+
orders.push(order);
50+
};
51+
52+
Restaurant.prototype.prepareOrders = function () {
53+
var summary = "";
54+
for (var i = 0, len = orders.length; i < len; i++) {
55+
summary += orders[i].deliver();
56+
}
57+
return summary;
58+
};
59+
60+
return Restaurant;
61+
})();
62+
63+
// ==============================
64+
// CONCRETE CUSTOMER
65+
// ==============================
66+
67+
var Customer = (function () {
68+
function Customer() {}
69+
70+
Customer.prototype.pay = function () {
71+
return "Payment OK!\n";
72+
};
73+
74+
return Customer;
75+
})();
76+
77+
// ==============================
78+
// CLIENT CODE
79+
// ==============================
80+
81+
var customer = new Customer(),
82+
order = new TexMex(customer),
83+
restaurant = new Restaurant();
84+
85+
restaurant.addOrder(order);
86+
console.log(restaurant.prepareOrders());
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// ==============================
2+
// ABSTRACT ORDER
3+
// ==============================
4+
5+
class Order {
6+
constructor() {
7+
if (new.target !== undefined) {
8+
throw new Error("You cannot instantiate an abstract class!");
9+
}
10+
}
11+
12+
deliver() {
13+
throw new Error("You cannot call an abstract method!");
14+
}
15+
}
16+
17+
// ==============================
18+
// CONCRETE ORDER
19+
// ==============================
20+
21+
class TexMex extends Order {
22+
constructor(customer) {
23+
super();
24+
this._customer = customer;
25+
}
26+
27+
deliver() {
28+
return this._customer.pay();
29+
}
30+
}
31+
32+
// ==============================
33+
// CONCRETE RESTAURANT
34+
// ==============================
35+
36+
class Restaurant {
37+
constructor() {
38+
this._orders = [];
39+
}
40+
41+
addOrder(order) {
42+
this._orders.push(order);
43+
}
44+
45+
prepareOrders() {
46+
let summary = "";
47+
for (let order of this._orders) {
48+
summary += order.deliver();
49+
}
50+
return summary;
51+
}
52+
}
53+
54+
// ==============================
55+
// CONCRETE CUSTOMER
56+
// ==============================
57+
58+
class Customer {
59+
pay() {
60+
return "Payment OK!\n";
61+
}
62+
}
63+
64+
// ==============================
65+
// CLIENT CODE
66+
// ==============================
67+
68+
let customer = new Customer(),
69+
order = new TexMex(customer),
70+
restaurant = new Restaurant();
71+
72+
restaurant.addOrder(order);
73+
console.log(restaurant.prepareOrders());

0 commit comments

Comments
 (0)