diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000..afa7ccb
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+v11.10.1
diff --git a/.travis.yml b/.travis.yml
index dcafd89..3e74ce3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,5 @@
language: node_js
-node_js:
- - '11'
-
branches:
only:
- master
diff --git a/README.md b/README.md
index a9a6ac6..800ff1f 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,9 @@
Design Patterns - a game to get familiar with the design patterns implemented in JavaScript, test your knowledge or simply for fun.
-### :zap: [PLAY HERE](http://design-patterns-javascript.surge.sh/)
+### :zap: [PLAY HERE](https://design-patterns-javascript.surge.sh/)
-
+[
](https://design-patterns-javascript.surge.sh/)
- [About](#about)
- [How To Run Locally](#how-to-run-locally)
diff --git a/src/static/patterns/behavioral_chainOfResponsibility.js b/src/static/patterns/behavioral_chainOfResponsibility.js
new file mode 100644
index 0000000..7477a7c
--- /dev/null
+++ b/src/static/patterns/behavioral_chainOfResponsibility.js
@@ -0,0 +1,131 @@
+const CHAIN_OF_RESPONSIBILITY = {
+ id: 'chain_of_responsibility',
+ name: 'Chain of Responsibility',
+ type: 'behavioral',
+ hint: 'delegates commands to a chain of processing objects',
+ codeES5: `function ShoppingCart() {
+this.products = [];
+
+this.addProduct = function(p) {
+ this.products.push(p);
+};
+}
+
+function Discount() {
+this.calc = function(products) {
+ var ndiscount = new NumberDiscount();
+ var pdiscount = new PriceDiscount();
+ var none = new NoneDiscount();
+
+ ndiscount.setNext(pdiscount);
+ pdiscount.setNext(none);
+
+ return ndiscount.exec(products);
+};
+}
+
+function NumberDiscount() {
+this.next = null;
+this.setNext = function(fn) {
+ this.next = fn;
+};
+
+this.exec = function(products) {
+ var result = 0;
+ if (products.length > 3) result = 0.05;
+
+ return result + this.next.exec(products);
+};
+}
+
+function PriceDiscount() {
+this.next = null;
+this.setNext = function(fn) {
+ this.next = fn;
+};
+this.exec = function(products) {
+ var result = 0;
+ var total = products.reduce(function(a, b) {
+ return a + b;
+ });
+
+ if (total >= 500) result = 0.1;
+
+ return result + this.next.exec(products);
+};
+}
+
+function NoneDiscount() {
+this.exec = function() {
+ return 0;
+};
+}
+
+module.exports = [ShoppingCart, Discount];`,
+ codeES6: `class ShoppingCart {
+constructor() {
+ this.products = [];
+}
+
+addProduct(p) {
+ this.products.push(p);
+}
+}
+
+class Discount {
+calc(products) {
+ let ndiscount = new NumberDiscount();
+ let pdiscount = new PriceDiscount();
+ let none = new NoneDiscount();
+ ndiscount.setNext(pdiscount);
+ pdiscount.setNext(none);
+ return ndiscount.exec(products);
+}
+}
+
+class NumberDiscount {
+constructor() {
+ this.next = null;
+}
+
+setNext(fn) {
+ this.next = fn;
+}
+
+exec(products) {
+ let result = 0;
+ if (products.length > 3) result = 0.05;
+
+ return result + this.next.exec(products);
+}
+}
+
+class PriceDiscount {
+constructor() {
+ this.next = null;
+}
+
+setNext(fn) {
+ this.next = fn;
+}
+
+exec(products) {
+ let result = 0;
+ let total = products.reduce((a, b) => a + b);
+
+ if (total >= 500) result = 0.1;
+
+ return result + this.next.exec(products);
+}
+}
+
+class NoneDiscount {
+exec() {
+ return 0;
+}
+}
+
+export { ShoppingCart, Discount };`
+};
+
+export default CHAIN_OF_RESPONSIBILITY;
diff --git a/src/static/patterns/behavioral_command.js b/src/static/patterns/behavioral_command.js
new file mode 100644
index 0000000..16cd307
--- /dev/null
+++ b/src/static/patterns/behavioral_command.js
@@ -0,0 +1,111 @@
+const COMMAND = {
+ id: 'command',
+ name: 'Command',
+ type: 'behavioral',
+ hint: 'creates objects which encapsulate actions and parameters',
+ codeES5: `function Cockpit(instruction) {
+this.instruction = instruction;
+}
+Cockpit.prototype.execute = function() {
+this.instruction.execute();
+};
+
+function Turbine() {
+this.speed = 0;
+this.state = false;
+}
+
+Turbine.prototype.on = function() {
+this.state = true;
+this.speed = 100;
+};
+
+Turbine.prototype.off = function() {
+this.speed = 0;
+this.state = false;
+};
+
+Turbine.prototype.speedDown = function() {
+if (!this.state) return;
+
+this.speed -= 100;
+};
+
+Turbine.prototype.speedUp = function() {
+if (!this.state) return;
+
+this.speed += 100;
+};
+
+function OnInstruction(turbine) {
+this.turbine = turbine;
+}
+OnInstruction.prototype.execute = function() {
+this.turbine.on();
+};
+
+function OffInstruction(turbine) {
+this.turbine = turbine;
+}
+OffInstruction.prototype.execute = function() {
+this.turbine.off();
+};
+
+function SpeedUpInstruction(turbine) {
+this.turbine = turbine;
+}
+SpeedUpInstruction.prototype.execute = function() {
+this.turbine.speedUp();
+};
+
+function SpeedDownInstruction(turbine) {
+this.turbine = turbine;
+}
+SpeedDownInstruction.prototype.execute = function() {
+this.turbine.speedDown();
+};
+
+module.exports = [Cockpit, Turbine, OnInstruction, OffInstruction, SpeedUpInstruction, SpeedDownInstruction];`,
+ codeES6: `class Cockpit {
+constructor(instruction) {
+ this.instruction = instruction;
+}
+execute() {
+ this.instruction.execute();
+}
+}
+
+class Turbine {
+constructor() {
+ this.state = false;
+}
+on() {
+ this.state = true;
+}
+off() {
+ this.state = false;
+}
+}
+
+class OnInstruction {
+constructor(turbine) {
+ this.turbine = turbine;
+}
+execute() {
+ this.turbine.on();
+}
+}
+
+class OffInstruction {
+constructor(turbine) {
+ this.turbine = turbine;
+}
+execute() {
+ this.turbine.off();
+}
+}
+
+export { Cockpit, Turbine, OnInstruction, OffInstruction };`
+};
+
+export default COMMAND;
diff --git a/src/static/patterns/behavioral_interpreter.js b/src/static/patterns/behavioral_interpreter.js
new file mode 100644
index 0000000..f7dbe49
--- /dev/null
+++ b/src/static/patterns/behavioral_interpreter.js
@@ -0,0 +1,68 @@
+const INTERPRETER = {
+ id: 'interpteter',
+ name: 'Interpreter',
+ type: 'behavioral',
+ hint: 'implements a specialized language',
+ codeES5: `function Sum(left, right) {
+this.left = left;
+this.right = right;
+}
+
+Sum.prototype.pattern = function() {
+return this.left.pattern() + this.right.pattern();
+};
+
+function Min(left, right) {
+this.left = left;
+this.right = right;
+}
+
+Min.prototype.pattern = function() {
+return this.left.pattern() - this.right.pattern();
+};
+
+function Num(val) {
+this.val = val;
+}
+
+Num.prototype.pattern = function() {
+return this.val;
+};
+
+module.exports = [Num, Min, Sum];`,
+ codeES6: `class Sum {
+constructor(left, right) {
+ this.left = left;
+ this.right = right;
+}
+
+pattern() {
+ return this.left.pattern() + this.right.pattern();
+}
+}
+
+class Min {
+constructor(left, right) {
+ this.left = left;
+ this.right = right;
+}
+
+pattern() {
+ return this.left.pattern() - this.right.pattern();
+}
+}
+
+class Num {
+constructor(val) {
+ this.val = val;
+}
+
+pattern() {
+ return this.val;
+}
+}
+
+export { Num, Min, Sum };`
+};
+
+export default INTERPRETER;
diff --git a/src/static/patterns/behavioral_iterator.js b/src/static/patterns/behavioral_iterator.js
new file mode 100644
index 0000000..30272b1
--- /dev/null
+++ b/src/static/patterns/behavioral_iterator.js
@@ -0,0 +1,40 @@
+const ITERATOR = {
+ id: 'iterator',
+ name: 'Iterator',
+ type: 'behavioral',
+ hint:
+ 'accesses the elements of an object sequentially without exposing its underlying representation',
+ codeES5: `function Pattern(el) {
+this.index = 0;
+this.elements = el;
+}
+
+Pattern.prototype = {
+next: function() {
+ return this.elements[this.index++];
+},
+hasNext: function() {
+ return this.index < this.elements.length;
+}
+};
+
+module.exports = Pattern;`,
+ codeES6: `class Pattern {
+constructor(el) {
+ this.index = 0;
+ this.elements = el;
+}
+
+next() {
+ return this.elements[this.index++];
+}
+
+hasNext() {
+ return this.index < this.elements.length;
+}
+}
+
+export default Pattern;`
+};
+
+export default ITERATOR;
diff --git a/src/static/patterns/behavioral_mediator.js b/src/static/patterns/behavioral_mediator.js
new file mode 100644
index 0000000..fff02ce
--- /dev/null
+++ b/src/static/patterns/behavioral_mediator.js
@@ -0,0 +1,55 @@
+const MEDIATOR = {
+ id: 'mediator',
+ name: 'Mediator',
+ type: 'behavioral',
+ hint:
+ 'allows loose coupling between classes by being the only class that has detailed knowledge of their methods',
+ codeES5: `function TrafficTower() {
+this.airplanes = [];
+}
+
+TrafficTower.prototype.requestPositions = function() {
+return this.airplanes.map(function(airplane) {
+ return airplane.position;
+});
+};
+
+function Airplane(position, trafficTower) {
+this.position = position;
+this.trafficTower = trafficTower;
+this.trafficTower.airplanes.push(this);
+}
+
+Airplane.prototype.requestPositions = function() {
+return this.trafficTower.requestPositions();
+};
+
+module.exports = [TrafficTower, Airplane];`,
+ codeES6: `class TrafficTower {
+constructor() {
+ this.airplanes = [];
+}
+
+requestPositions() {
+ return this.airplanes.map(airplane => {
+ return airplane.position;
+ });
+}
+}
+
+class Airplane {
+constructor(position, trafficTower) {
+ this.position = position;
+ this.trafficTower = trafficTower;
+ this.trafficTower.airplanes.push(this);
+}
+
+requestPositions() {
+ return this.trafficTower.requestPositions();
+}
+}
+
+export { TrafficTower, Airplane };`
+};
+
+export default MEDIATOR;
diff --git a/src/static/patterns/behavioral_memento.js b/src/static/patterns/behavioral_memento.js
new file mode 100644
index 0000000..1cef9c1
--- /dev/null
+++ b/src/static/patterns/behavioral_memento.js
@@ -0,0 +1,64 @@
+const MEMENTO = {
+ id: 'memento',
+ name: 'Memento',
+ type: 'behavioral',
+ hint: 'provides the ability to restore an object to its previous state',
+ codeES5: `function Pattern(value) {
+this.value = value;
+}
+
+var originator = {
+store: function(val) {
+ return new Pattern(val);
+},
+restore: function(pattern) {
+ return pattern.value;
+}
+};
+
+function Caretaker() {
+this.values = [];
+}
+
+Caretaker.prototype.addPattern = function(pattern) {
+this.values.push(pattern);
+};
+
+Caretaker.prototype.getPattern = function(index) {
+return this.values[index];
+};
+
+module.exports = [originator, Caretaker];`,
+ codeES6: `class Pattern {
+constructor(value) {
+ this.value = value;
+}
+}
+
+const originator = {
+store: function(val) {
+ return new Pattern(val);
+},
+restore: function(pattern) {
+ return pattern.value;
+}
+};
+
+class Caretaker {
+constructor() {
+ this.values = [];
+}
+
+addPattern(pattern) {
+ this.values.push(pattern);
+}
+
+getPattern(index) {
+ return this.values[index];
+}
+}
+
+export { originator, Caretaker };`
+};
+
+export default MEMENTO;
diff --git a/src/static/patterns/behavioral_observer.js b/src/static/patterns/behavioral_observer.js
new file mode 100644
index 0000000..29f1aa1
--- /dev/null
+++ b/src/static/patterns/behavioral_observer.js
@@ -0,0 +1,92 @@
+const OBSERVER = {
+ id: 'observer',
+ name: 'Observer',
+ type: 'behavioral',
+ hint: 'is a publish/subscribe pattern which allows a number of observer objects to see an event',
+ codeES5: `function Product() {
+this.price = 0;
+this.actions = [];
+}
+
+Product.prototype.setBasePrice = function(val) {
+this.price = val;
+this.notifyAll();
+};
+
+Product.prototype.register = function(observer) {
+this.actions.push(observer);
+};
+
+Product.prototype.unregister = function(observer) {
+this.actions.remove.filter(function(el) {
+ return el !== observer;
+});
+};
+
+Product.prototype.notifyAll = function() {
+return this.actions.forEach(
+ function(el) {
+ el.update(this);
+ }.bind(this)
+);
+};
+
+var fees = {
+update: function(product) {
+ product.price = product.price * 1.2;
+}
+};
+
+var proft = {
+update: function(product) {
+ product.price = product.price * 2;
+}
+};
+
+module.exports = [Product, fees, proft];`,
+ codeES6: `class Product {
+constructor() {
+ this.price = 0;
+ this.actions = [];
+}
+
+setBasePrice(val) {
+ this.price = val;
+ this.notifyAll();
+}
+
+register(observer) {
+ this.actions.push(observer);
+}
+
+unregister(observer) {
+ this.actions.remove.filter(function(el) {
+ return el !== observer;
+ });
+}
+
+notifyAll() {
+ return this.actions.forEach(
+ function(el) {
+ el.update(this);
+ }.bind(this)
+ );
+}
+}
+
+class fees {
+update(product) {
+ product.price = product.price * 1.2;
+}
+}
+
+class proft {
+update(product) {
+ product.price = product.price * 2;
+}
+}
+
+export { Product, fees, proft };`
+};
+
+export default OBSERVER;
diff --git a/src/static/patterns/behavioral_state.js b/src/static/patterns/behavioral_state.js
new file mode 100644
index 0000000..c89ed61
--- /dev/null
+++ b/src/static/patterns/behavioral_state.js
@@ -0,0 +1,78 @@
+const STATE = {
+ id: 'state',
+ name: 'State',
+ type: 'behavioral',
+ hint: 'allows an object to alter its behavior when its internal state changes',
+ codeES5: `function Order() {
+this.pattern = new WaitingForPayment();
+
+this.nextPattern = function() {
+ this.pattern = this.pattern.next();
+};
+}
+
+function WaitingForPayment() {
+this.name = 'waitingForPayment';
+this.next = function() {
+ return new Shipping();
+};
+}
+
+function Shipping() {
+this.name = 'shipping';
+this.next = function() {
+ return new Delivered();
+};
+}
+
+function Delivered() {
+this.name = 'delivered';
+this.next = function() {
+ return this;
+};
+}
+
+module.exports = Order;`,
+ codeES6: `class OrderStatus {
+constructor(name, nextStatus) {
+ this.name = name;
+ this.nextStatus = nextStatus;
+}
+
+next() {
+ return new this.nextStatus();
+}
+}
+
+class WaitingForPayment extends OrderStatus {
+constructor() {
+ super('waitingForPayment', Shipping);
+}
+}
+
+class Shipping extends OrderStatus {
+constructor() {
+ super('shipping', Delivered);
+}
+}
+
+class Delivered extends OrderStatus {
+constructor() {
+ super('delivered', Delivered);
+}
+}
+
+class Order {
+constructor() {
+ this.pattern = new WaitingForPayment();
+}
+
+nextPattern() {
+ this.pattern = this.pattern.next();
+}
+}
+
+export default Order;`
+};
+
+export default STATE;
diff --git a/src/static/patterns/behavioral_strategy.js b/src/static/patterns/behavioral_strategy.js
new file mode 100644
index 0000000..3d0cbc2
--- /dev/null
+++ b/src/static/patterns/behavioral_strategy.js
@@ -0,0 +1,62 @@
+const STRATEGY = {
+ id: 'strategy',
+ name: 'Strategy',
+ type: 'behavioral',
+ hint: 'allows one of a family of algorithms to be selected on-the-fly at runtime',
+ codeES5: `function ShoppingCart(discount) {
+this.discount = discount;
+this.amount = 0;
+}
+
+ShoppingCart.prototype.setAmount = function(amount) {
+this.amount = amount;
+};
+
+ShoppingCart.prototype.checkout = function() {
+return this.discount(this.amount);
+};
+
+function guestPattern(amount) {
+return amount;
+}
+
+function regularPattern(amount) {
+return amount * 0.9;
+}
+
+function premiumPattern(amount) {
+return amount * 0.8;
+}
+
+module.exports = [ShoppingCart, guestPattern, regularPattern, premiumPattern];`,
+ codeES6: `class ShoppingCart {
+constructor(discount) {
+ this.discount = discount;
+ this.amount = 0;
+}
+
+checkout() {
+ return this.discount(this.amount);
+}
+
+setAmount(amount) {
+ this.amount = amount;
+}
+}
+
+function guestPattern(amount) {
+return amount;
+}
+
+function regularPattern(amount) {
+return amount * 0.9;
+}
+
+function premiumPattern(amount) {
+return amount * 0.8;
+}
+
+export { ShoppingCart, guestPattern, regularPattern, premiumPattern };`
+};
+
+export default STRATEGY;
diff --git a/src/static/patterns/behavioral_template.js b/src/static/patterns/behavioral_template.js
new file mode 100644
index 0000000..1fd1bd3
--- /dev/null
+++ b/src/static/patterns/behavioral_template.js
@@ -0,0 +1,67 @@
+const TEMPLATE = {
+ id: 'template',
+ name: 'Template',
+ type: 'behavioral',
+ hint:
+ 'defines the skeleton of an algorithm as an abstract class, allowing its subclasses to provide concrete behavior',
+ codeES5: `function Tax() {}
+
+Tax.prototype.calc = function(value) {
+if (value >= 1000) value = this.overThousand(value);
+
+return this.complementaryFee(value);
+};
+
+Tax.prototype.complementaryFee = function(value) {
+return value + 10;
+};
+
+function Tax1() {}
+Tax1.prototype = Object.create(Tax.prototype);
+
+Tax1.prototype.overThousand = function(value) {
+return value * 1.1;
+};
+
+function Tax2() {}
+Tax2.prototype = Object.create(Tax.prototype);
+
+Tax2.prototype.overThousand = function(value) {
+return value * 1.2;
+};
+
+module.exports = [Tax1, Tax2];`,
+ codeES6: `class Tax {
+calc(value) {
+ if (value >= 1000) value = this.overThousand(value);
+
+ return this.complementaryFee(value);
+}
+
+complementaryFee(value) {
+ return value + 10;
+}
+}
+
+class Tax1 extends Tax {
+constructor() {
+ super();
+}
+overThousand(value) {
+ return value * 1.1;
+}
+}
+
+class Tax2 extends Tax {
+constructor() {
+ super();
+}
+overThousand(value) {
+ return value * 1.2;
+}
+}
+
+export { Tax1, Tax2 };`
+};
+
+export default TEMPLATE;
diff --git a/src/static/patterns/behavioral_visitor.js b/src/static/patterns/behavioral_visitor.js
new file mode 100644
index 0000000..42f4eb9
--- /dev/null
+++ b/src/static/patterns/behavioral_visitor.js
@@ -0,0 +1,64 @@
+const VISITOR = {
+ id: 'visitor',
+ name: 'Visitor',
+ type: 'behavioral',
+ hint:
+ 'separates an algorithm from an object structure by moving the hierarchy of methods into one object',
+ codeES5: `function bonusPattern(employee) {
+if (employee instanceof Manager) employee.bonus = employee.salary * 2;
+if (employee instanceof Developer) employee.bonus = employee.salary;
+}
+
+function Employee() {
+this.bonus = 0;
+}
+
+Employee.prototype.accept = function(item) {
+item(this);
+};
+
+function Manager(salary) {
+this.salary = salary;
+}
+
+Manager.prototype = Object.create(Employee.prototype);
+
+function Developer(salary) {
+this.salary = salary;
+}
+
+Developer.prototype = Object.create(Employee.prototype);
+
+module.exports = [Developer, Manager, bonusPattern];`,
+ codeES6: `function bonusPattern(employee) {
+if (employee instanceof Manager) employee.bonus = employee.salary * 2;
+if (employee instanceof Developer) employee.bonus = employee.salary;
+}
+
+class Employee {
+constructor(salary) {
+ this.bonus = 0;
+ this.salary = salary;
+}
+
+accept(item) {
+ item(this);
+}
+}
+
+class Manager extends Employee {
+constructor(salary) {
+ super(salary);
+}
+}
+
+class Developer extends Employee {
+constructor(salary) {
+ super(salary);
+}
+}
+
+export { Developer, Manager, bonusPattern };`
+};
+
+export default VISITOR;
diff --git a/src/static/patterns/creational_abstractFactory.js b/src/static/patterns/creational_abstractFactory.js
new file mode 100644
index 0000000..dd8eaff
--- /dev/null
+++ b/src/static/patterns/creational_abstractFactory.js
@@ -0,0 +1,58 @@
+const ABSTRACT_FACTORY = {
+ id: 'abstract_factory',
+ name: 'Abstract Factory',
+ type: 'creational',
+ hint: 'groups object factories that have a common theme',
+ codeES5: `function droidProducer(kind) {
+if (kind === 'battle') return battleDroidPattern;
+return pilotDroidPattern;
+}
+
+function battleDroidPattern() {
+return new B1();
+}
+
+function pilotDroidPattern() {
+return new Rx24();
+}
+
+function B1() {}
+B1.prototype.info = function() {
+return 'B1, Battle Droid';
+};
+
+function Rx24() {}
+Rx24.prototype.info = function() {
+return 'Rx24, Pilot Droid';
+};
+
+module.exports = droidProducer;`,
+ codeES6: `function droidProducer(kind) {
+if (kind === 'battle') return battleDroidPattern;
+return pilotDroidPattern;
+}
+
+function battleDroidPattern() {
+return new B1();
+}
+
+function pilotDroidPattern() {
+return new Rx24();
+}
+
+class B1 {
+info() {
+ return 'B1, Battle Droid';
+}
+}
+
+class Rx24 {
+info() {
+ return 'Rx24, Pilot Droid';
+}
+}
+
+export default droidProducer;`
+};
+
+export default ABSTRACT_FACTORY;
diff --git a/src/static/patterns/creational_builder.js b/src/static/patterns/creational_builder.js
new file mode 100644
index 0000000..4a5ec31
--- /dev/null
+++ b/src/static/patterns/creational_builder.js
@@ -0,0 +1,72 @@
+const BUILDER = {
+ id: 'builder',
+ name: 'Builder',
+ type: 'creational',
+ hint: 'constructs complex objects by separating construction and representation',
+ codeES5: `function Request() {
+this.url = '';
+this.method = '';
+this.payload = {};
+}
+
+function RequestPattern() {
+this.request = new Request();
+
+this.forUrl = function(url) {
+ this.request.url = url;
+ return this;
+};
+
+this.useMethod = function(method) {
+ this.request.method = method;
+ return this;
+};
+
+this.payload = function(payload) {
+ this.request.payload = payload;
+ return this;
+};
+
+this.build = function() {
+ return this.request;
+};
+}
+
+module.exports = RequestPattern;`,
+ codeES6: `class Request {
+constructor() {
+ this.url = '';
+ this.method = '';
+ this.payload = {};
+}
+}
+
+class RequestPattern {
+constructor() {
+ this.request = new Request();
+}
+
+forUrl(url) {
+ this.request.url = url;
+ return this;
+}
+
+useMethod(method) {
+ this.request.method = method;
+ return this;
+}
+
+payload(payload) {
+ this.request.payload = payload;
+ return this;
+}
+
+build() {
+ return this.request;
+}
+}
+
+export default RequestPattern;`
+};
+
+export default BUILDER;
diff --git a/src/static/patterns/creational_factory.js b/src/static/patterns/creational_factory.js
new file mode 100644
index 0000000..f56d807
--- /dev/null
+++ b/src/static/patterns/creational_factory.js
@@ -0,0 +1,36 @@
+const FACTORY = {
+ id: 'factory',
+ name: 'Factory',
+ type: 'creational',
+ hint: 'creates objects without specifying the exact class to create',
+ codeES5: `function teslaPattern(type) {
+if (type === 'ModelX') return new Tesla(type, 108000, 300);
+if (type === 'ModelS') return new Tesla(type, 111000, 320);
+}
+
+function Tesla(model, price, maxSpeed) {
+this.model = model;
+this.price = price;
+this.maxSpeed = maxSpeed;
+}
+
+module.exports = teslaPattern;`,
+ codeES6: `class TeslaPattern {
+create(type) {
+ if (type === 'ModelX') return new Tesla(type, 108000, 300);
+ if (type === 'ModelS') return new Tesla(type, 111000, 320);
+}
+}
+
+class Tesla {
+constructor(model, price, maxSpeed) {
+ this.model = model;
+ this.price = price;
+ this.maxSpeed = maxSpeed;
+}
+}
+
+export default TeslaPattern;`
+};
+
+export default FACTORY;
diff --git a/src/static/patterns/creational_prototype.js b/src/static/patterns/creational_prototype.js
new file mode 100644
index 0000000..c6e5437
--- /dev/null
+++ b/src/static/patterns/creational_prototype.js
@@ -0,0 +1,30 @@
+const PROTOTYPE = {
+ id: 'prototype',
+ name: 'Prototype',
+ type: 'creational',
+ hint: 'creates objects by cloning an existing object',
+ codeES5: `function Sheep(name, weight) {
+this.name = name;
+this.weight = weight;
+}
+
+Sheep.prototype.clone = function() {
+return new Sheep(this.name, this.weight);
+};
+
+module.exports = Sheep;`,
+ codeES6: `class Sheep {
+constructor(name, weight) {
+ this.name = name;
+ this.weight = weight;
+}
+
+clone() {
+ return new Sheep(this.name, this.weight);
+}
+}
+
+export default Sheep;`
+};
+
+export default PROTOTYPE;
diff --git a/src/static/patterns/creational_singleton.js b/src/static/patterns/creational_singleton.js
new file mode 100644
index 0000000..dfaa7dd
--- /dev/null
+++ b/src/static/patterns/creational_singleton.js
@@ -0,0 +1,28 @@
+const SINGLETON = {
+ id: 'singleton',
+ name: 'Singleton',
+ type: 'creational',
+ hint: 'restricts object creation for a class to only one instance',
+ codeES5: `function Person() {
+if (typeof Person.instance === 'object') return Person.instance;
+
+Person.instance = this;
+
+return this;
+}
+
+module.exports = Person;`,
+ codeES6: `class Person {
+constructor() {
+ if (typeof Person.instance === 'object') {
+ return Person.instance;
+ }
+ Person.instance = this;
+ return this;
+}
+}
+
+export default Person;`
+};
+
+export default SINGLETON;
diff --git a/src/static/patterns/index.js b/src/static/patterns/index.js
index bbb7350..f5df231 100644
--- a/src/static/patterns/index.js
+++ b/src/static/patterns/index.js
@@ -1,1592 +1,53 @@
-const patterns = [
- /*
- * Abstract
- */
- {
- id: 'abstract_factory',
- name: 'Abstract Factory',
- type: 'creational',
- hint: 'groups object factories that have a common theme',
- codeES5: `function droidProducer(kind) {
- if (kind === 'battle') return battleDroidPattern;
- return pilotDroidPattern;
-}
-
-function battleDroidPattern() {
- return new B1();
-}
-
-function pilotDroidPattern() {
- return new Rx24();
-}
-
-function B1() {}
-B1.prototype.info = function() {
- return 'B1, Battle Droid';
-};
-
-function Rx24() {}
-Rx24.prototype.info = function() {
- return 'Rx24, Pilot Droid';
-};
-
-module.exports = droidProducer;`,
- codeES6: `function droidProducer(kind) {
- if (kind === 'battle') return battleDroidPattern;
- return pilotDroidPattern;
-}
-
-function battleDroidPattern() {
- return new B1();
-}
-
-function pilotDroidPattern() {
- return new Rx24();
-}
-
-class B1 {
- info() {
- return 'B1, Battle Droid';
- }
-}
-
-class Rx24 {
- info() {
- return 'Rx24, Pilot Droid';
- }
-}
-
-export default droidProducer;`
- },
- /*
- * Builder
- */
- {
- id: 'builder',
- name: 'Builder',
- type: 'creational',
- hint: 'constructs complex objects by separating construction and representation',
- codeES5: `function Request() {
- this.url = '';
- this.method = '';
- this.payload = {};
-}
-
-function RequestPattern() {
- this.request = new Request();
-
- this.forUrl = function(url) {
- this.request.url = url;
- return this;
- };
-
- this.useMethod = function(method) {
- this.request.method = method;
- return this;
- };
-
- this.payload = function(payload) {
- this.request.payload = payload;
- return this;
- };
-
- this.build = function() {
- return this.request;
- };
-}
-
-module.exports = RequestPattern;`,
- codeES6: `class Request {
- constructor() {
- this.url = '';
- this.method = '';
- this.payload = {};
- }
-}
-
-class RequestPattern {
- constructor() {
- this.request = new Request();
- }
-
- forUrl(url) {
- this.request.url = url;
- return this;
- }
-
- useMethod(method) {
- this.request.method = method;
- return this;
- }
-
- payload(payload) {
- this.request.payload = payload;
- return this;
- }
-
- build() {
- return this.request;
- }
-}
-
-export default RequestPattern;`
- },
- /*
- * Factory
- */
- {
- id: 'factory',
- name: 'Factory',
- type: 'creational',
- hint: 'creates objects without specifying the exact class to create',
- codeES5: `function teslaPattern(type) {
- if (type === 'ModelX') return new Tesla(type, 108000, 300);
- if (type === 'ModelS') return new Tesla(type, 111000, 320);
-}
-
-function Tesla(model, price, maxSpeed) {
- this.model = model;
- this.price = price;
- this.maxSpeed = maxSpeed;
-}
-
-module.exports = teslaPattern;`,
- codeES6: `class TeslaPattern {
- create(type) {
- if (type === 'ModelX') return new Tesla(type, 108000, 300);
- if (type === 'ModelS') return new Tesla(type, 111000, 320);
- }
-}
-
-class Tesla {
- constructor(model, price, maxSpeed) {
- this.model = model;
- this.price = price;
- this.maxSpeed = maxSpeed;
- }
-}
-
-export default TeslaPattern;`
- },
- /*
- * Prototype
- */
- {
- id: 'prototype',
- name: 'Prototype',
- type: 'creational',
- hint: 'creates objects by cloning an existing object',
- codeES5: `function Sheep(name, weight) {
- this.name = name;
- this.weight = weight;
-}
-
-Sheep.prototype.clone = function() {
- return new Sheep(this.name, this.weight);
-};
-
-module.exports = Sheep;`,
- codeES6: `class Sheep {
- constructor(name, weight) {
- this.name = name;
- this.weight = weight;
- }
-
- clone() {
- return new Sheep(this.name, this.weight);
- }
-}
-
-export default Sheep;`
- },
- /*
- * Singleton
- */
- {
- id: 'singleton',
- name: 'Singleton',
- type: 'creational',
- hint: 'restricts object creation for a class to only one instance',
- codeES5: `function Person() {
- if (typeof Person.instance === 'object') return Person.instance;
-
- Person.instance = this;
-
- return this;
-}
-
-module.exports = Person;`,
- codeES6: `class Person {
- constructor() {
- if (typeof Person.instance === 'object') {
- return Person.instance;
- }
- Person.instance = this;
- return this;
- }
-}
-
-export default Person;`
- },
- /*
- * Adapter
- */
- {
- id: 'adapter',
- name: 'Adapter',
- type: 'structural',
- hint: `allows classes with incompatible interfaces to work together by wrapping its
- own interface around that of an already existing class`,
- codeES5: `function Soldier(lvl) {
- this.lvl = lvl;
-}
-
-Soldier.prototype.attack = function() {
- return this.lvl * 1;
-};
-
-function Jedi(lvl) {
- this.lvl = lvl;
-}
-
-Jedi.prototype.attackWithSaber = function() {
- return this.lvl * 100;
-};
-
-function JediPattern(jedi) {
- this.jedi = jedi;
-}
-
-JediPattern.prototype.attack = function() {
- return this.jedi.attackWithSaber();
-};
-
-module.exports = [Soldier, Jedi, JediPattern];`,
- codeES6: `class Soldier {
- constructor(level) {
- this.level = level;
- }
-
- attack() {
- return this.level * 1;
- }
-}
-
-class Jedi {
- constructor(level) {
- this.level = level;
- }
-
- attackWithSaber() {
- return this.level * 100;
- }
-}
-
-class JediPattern {
- constructor(jedi) {
- this.jedi = jedi;
- }
-
- attack() {
- return this.jedi.attackWithSaber();
- }
-}
-
-export { Soldier, Jedi, JediPattern };`
- },
- /*
- * Bridge
- */
- {
- id: 'bridge',
- name: 'Bridge',
- type: 'structural',
- hint: 'decouples an abstraction from its implementation so that the two can vary independently',
- codeES5: `function EpsonPrinter(ink) {
- this.ink = ink();
-}
-EpsonPrinter.prototype.print = function() {
- return 'Printer: Epson, Ink: ' + this.ink;
-};
-
-function HPprinter(ink) {
- this.ink = ink();
-}
-HPprinter.prototype.print = function() {
- return 'Printer: HP, Ink: ' + this.ink;
-};
-
-function acrylicInk() {
- return 'acrylic-based';
-}
-
-function alcoholInk() {
- return 'alcohol-based';
-}
-
-module.exports = [EpsonPrinter, HPprinter, acrylicInk, alcoholInk];`,
- codeES6: `class Printer {
- constructor(ink) {
- this.ink = ink;
- }
-}
-
-class EpsonPrinter extends Printer {
- constructor(ink) {
- super(ink);
- }
-
- print() {
- return 'Printer: Epson, Ink: ' + this.ink.get();
- }
-}
-
-class HPprinter extends Printer {
- constructor(ink) {
- super(ink);
- }
-
- print() {
- return 'Printer: HP, Ink: ' + this.ink.get();
- }
-}
-
-class Ink {
- constructor(type) {
- this.type = type;
- }
- get() {
- return this.type;
- }
-}
-
-class AcrylicInk extends Ink {
- constructor() {
- super('acrylic-based');
- }
-}
-
-class AlcoholInk extends Ink {
- constructor() {
- super('alcohol-based');
- }
-}
-
-export { EpsonPrinter, HPprinter, AcrylicInk, AlcoholInk };`
- },
- /*
- * Composite
- */
- {
- id: 'composite',
- name: 'Composite',
- type: 'structural',
- hint: 'composes zero-or-more similar objects so that they can be manipulated as one object',
- codeES5: `function EquipmentPattern(name) {
- this.equipments = [];
- this.name = name;
-}
-
-EquipmentPattern.prototype.add = function(equipment) {
- this.equipments.push(equipment);
-};
-
-EquipmentPattern.prototype.getPrice = function() {
- return this.equipments
- .map(function(equipment) {
- return equipment.getPrice();
- })
- .reduce(function(a, b) {
- return a + b;
- });
-};
+import ABSTRACT_FACTORY from './creational_abstractFactory';
+import BUILDER from './creational_builder';
+import FACTORY from './creational_factory';
+import PROTOTYPE from './creational_prototype';
+import SINGLETON from './creational_singleton';
+import ADAPTER from './structural_adapter';
+import BRIDGE from './structural_bridge';
+import COMPOSITE from './structural_composite';
+import DECORATOR from './structural_decorator';
+import FACADE from './structural_facade';
+import FLYWEIGHT from './structural_flyweight';
+import PROXY from './structural_proxy';
+import CHAIN_OF_RESPONSIBILITY from './behavioral_chainOfResponsibility';
+import COMMAND from './behavioral_command';
+import INTERPRETER from './behavioral_interpreter';
+import ITERATOR from './behavioral_iterator';
+import MEDIATOR from './behavioral_mediator';
+import MEMENTO from './behavioral_memento';
+import OBSERVER from './behavioral_observer';
+import STATE from './behavioral_state';
+import STRATEGY from './behavioral_strategy';
+import TEMPLATE from './behavioral_template';
+import VISITOR from './behavioral_visitor';
-function Equipment() {}
-
-Equipment.prototype.getPrice = function() {
- return this.price;
-};
-
-// -- leafs
-function FloppyDisk() {
- this.name = 'Floppy Disk';
- this.price = 70;
-}
-FloppyDisk.prototype = Object.create(Equipment.prototype);
-
-function HardDrive() {
- this.name = 'Hard Drive';
- this.price = 250;
-}
-HardDrive.prototype = Object.create(Equipment.prototype);
-
-function Memory() {
- this.name = '8gb memomry';
- this.price = 280;
-}
-Memory.prototype = Object.create(Equipment.prototype);
-
-module.exports = [EquipmentPattern, FloppyDisk, HardDrive, Memory];`,
- codeES6: `//Equipment
-class Equipment {
- getPrice() {
- return this.price || 0;
- }
-
- getName() {
- return this.name;
- }
-
- setName(name) {
- this.name = name;
- }
-}
-
-class Pattern extends Equipment {
- constructor() {
- super();
- this.equipments = [];
- }
-
- add(equipment) {
- this.equipments.push(equipment);
- }
-
- getPrice() {
- return this.equipments
- .map(equipment => {
- return equipment.getPrice();
- })
- .reduce((a, b) => {
- return a + b;
- });
- }
-}
-
-class Cabbinet extends Pattern {
- constructor() {
- super();
- this.setName('cabbinet');
- }
-}
-
-// --- leafs ---
-class FloppyDisk extends Equipment {
- constructor() {
- super();
- this.setName('Floppy Disk');
- this.price = 70;
- }
-}
-
-class HardDrive extends Equipment {
- constructor() {
- super();
- this.setName('Hard Drive');
- this.price = 250;
- }
-}
-
-class Memory extends Equipment {
- constructor() {
- super();
- this.setName('Memory');
- this.price = 280;
- }
-}
-
-export { Cabbinet, FloppyDisk, HardDrive, Memory };`
- },
- /*
- * Decorator
- */
- {
- id: 'decorator',
- name: 'Decorator',
- type: 'structural',
- hint: 'dynamically adds/overrides behaviour in an existing method of an object',
- codeES5: `function Pasta() {
- this.price = 0;
-}
-Pasta.prototype.getPrice = function() {
- return this.price;
-};
-
-function Penne() {
- this.price = 8;
-}
-Penne.prototype = Object.create(Pasta.prototype);
-
-function SaucePattern(pasta) {
- this.pasta = pasta;
-}
-
-SaucePattern.prototype.getPrice = function() {
- return this.pasta.getPrice() + 5;
-};
-
-function CheesePattern(pasta) {
- this.pasta = pasta;
-}
-
-CheesePattern.prototype.getPrice = function() {
- return this.pasta.getPrice() + 3;
-};
-
-module.exports = [Penne, SaucePattern, CheesePattern];`,
- codeES6: `class Pasta {
- constructor() {
- this.price = 0;
- }
- getPrice() {
- return this.price;
- }
-}
-
-class Penne extends Pasta {
- constructor() {
- super();
- this.price = 8;
- }
-}
-
-class PastaPattern extends Pasta {
- constructor(pasta) {
- super();
- this.pasta = pasta;
- }
-
- getPrice() {
- return this.pasta.getPrice();
- }
-}
-
-class SaucePattern extends PastaPattern {
- constructor(pasta) {
- super(pasta);
- }
-
- getPrice() {
- return super.getPrice() + 5;
- }
-}
-
-class CheesePattern extends PastaPattern {
- constructor(pasta) {
- super(pasta);
- }
-
- getPrice() {
- return super.getPrice() + 3;
- }
-}
-
-export { Penne, SaucePattern, CheesePattern };`
- },
- /*
- * Facade
- */
- {
- id: 'facade',
- name: 'Facade',
- type: 'structural',
- hint: 'provides a simplified interface to a large body of code',
- codeES5: `var shopPattern = {
- calc: function(price) {
- price = discount(price);
- price = fees(price);
- price += shipping();
- return price;
- }
-};
-
-function discount(value) {
- return value * 0.9;
-}
-
-function shipping() {
- return 5;
-}
-
-function fees(value) {
- return value * 1.05;
-}
-
-module.exports = shopPattern;`,
- codeES6: `class ShopPattern {
- constructor() {
- this.discount = new Discount();
- this.shipping = new Shipping();
- this.fees = new Fees();
- }
-
- calc(price) {
- price = this.discount.calc(price);
- price = this.fees.calc(price);
- price += this.shipping.calc();
- return price;
- }
-}
-
-class Discount {
- calc(value) {
- return value * 0.9;
- }
-}
-
-class Shipping {
- calc() {
- return 5;
- }
-}
-
-class Fees {
- calc(value) {
- return value * 1.05;
- }
-}
-
-export default ShopPattern;`
- },
- /*
- * Flyweight
- */
- {
- id: 'flyweight',
- name: 'Flyweight',
- type: 'structural',
- hint: 'reduces the cost of creating and manipulating a large number of similar objects',
- codeES5: `function Color(name) {
- this.name = name;
-}
-
-var colorCreator = {
- colors: {},
- create: function(name) {
- var color = this.colors[name];
- if (color) return color;
-
- this.colors[name] = new Color(name);
- return this.colors[name];
- }
-};
-
-module.exports = colorCreator;`,
- codeES6: `class Color {
- constructor(name) {
- this.name = name;
- }
-}
-
-class colorCreator {
- constructor(name) {
- this.colors = {};
- }
- create(name) {
- let color = this.colors[name];
- if (color) return color;
- this.colors[name] = new Color(name);
- return this.colors[name];
- }
-}
-
-export { colorCreator };`
- },
- /*
- * Proxy
- */
- {
- id: 'proxy',
- name: 'Proxy',
- type: 'structural',
- hint:
- 'provides a placeholder for another object to control access, reduce cost, and reduce complexity',
- codeES5: `function Car() {
- this.drive = function() {
- return 'driving';
- };
-}
-
-function CarPattern(driver) {
- this.driver = driver;
- this.drive = function() {
- if (driver.age < 18) return 'too young to drive';
- return new Car().drive();
- };
-}
-
-function Driver(age) {
- this.age = age;
-}
-
-module.exports = [Car, CarPattern, Driver];`,
- codeES6: `class Car {
- drive() {
- return 'driving';
- }
-}
-
-class CarPattern {
- constructor(driver) {
- this.driver = driver;
- }
- drive() {
- return this.driver.age < 18 ? 'too young to drive' : new Car().drive();
- }
-}
-
-class Driver {
- constructor(age) {
- this.age = age;
- }
-}
-
-export { Car, CarPattern, Driver };`
- },
- /*
- * Chain of Resp
- */
- {
- id: 'chain_of_responsibility',
- name: 'Chain of Responsibility',
- type: 'behavioral',
- hint: 'delegates commands to a chain of processing objects',
- codeES5: `function ShoppingCart() {
- this.products = [];
-
- this.addProduct = function(p) {
- this.products.push(p);
- };
-}
-
-function Discount() {
- this.calc = function(products) {
- var ndiscount = new NumberDiscount();
- var pdiscount = new PriceDiscount();
- var none = new NoneDiscount();
-
- ndiscount.setNext(pdiscount);
- pdiscount.setNext(none);
-
- return ndiscount.exec(products);
- };
-}
-
-function NumberDiscount() {
- this.next = null;
- this.setNext = function(fn) {
- this.next = fn;
- };
-
- this.exec = function(products) {
- var result = 0;
- if (products.length > 3) result = 0.05;
-
- return result + this.next.exec(products);
- };
-}
-
-function PriceDiscount() {
- this.next = null;
- this.setNext = function(fn) {
- this.next = fn;
- };
- this.exec = function(products) {
- var result = 0;
- var total = products.reduce(function(a, b) {
- return a + b;
- });
-
- if (total >= 500) result = 0.1;
-
- return result + this.next.exec(products);
- };
-}
-
-function NoneDiscount() {
- this.exec = function() {
- return 0;
- };
-}
-
-module.exports = [ShoppingCart, Discount];`,
- codeES6: `class ShoppingCart {
- constructor() {
- this.products = [];
- }
-
- addProduct(p) {
- this.products.push(p);
- }
-}
-
-class Discount {
- calc(products) {
- let ndiscount = new NumberDiscount();
- let pdiscount = new PriceDiscount();
- let none = new NoneDiscount();
- ndiscount.setNext(pdiscount);
- pdiscount.setNext(none);
- return ndiscount.exec(products);
- }
-}
-
-class NumberDiscount {
- constructor() {
- this.next = null;
- }
-
- setNext(fn) {
- this.next = fn;
- }
-
- exec(products) {
- let result = 0;
- if (products.length > 3) result = 0.05;
-
- return result + this.next.exec(products);
- }
-}
-
-class PriceDiscount {
- constructor() {
- this.next = null;
- }
-
- setNext(fn) {
- this.next = fn;
- }
-
- exec(products) {
- let result = 0;
- let total = products.reduce((a, b) => a + b);
-
- if (total >= 500) result = 0.1;
-
- return result + this.next.exec(products);
- }
-}
-
-class NoneDiscount {
- exec() {
- return 0;
- }
-}
-
-export { ShoppingCart, Discount };`
- },
- /*
- * Command
- */
- {
- id: 'command',
- name: 'Command',
- type: 'behavioral',
- hint: 'creates objects which encapsulate actions and parameters',
- codeES5: `function Cockpit(instruction) {
- this.instruction = instruction;
-}
-Cockpit.prototype.execute = function() {
- this.instruction.execute();
-};
-
-function Turbine() {
- this.speed = 0;
- this.state = false;
-}
-
-Turbine.prototype.on = function() {
- this.state = true;
- this.speed = 100;
-};
-
-Turbine.prototype.off = function() {
- this.speed = 0;
- this.state = false;
-};
-
-Turbine.prototype.speedDown = function() {
- if (!this.state) return;
-
- this.speed -= 100;
-};
-
-Turbine.prototype.speedUp = function() {
- if (!this.state) return;
-
- this.speed += 100;
-};
-
-function OnInstruction(turbine) {
- this.turbine = turbine;
-}
-OnInstruction.prototype.execute = function() {
- this.turbine.on();
-};
-
-function OffInstruction(turbine) {
- this.turbine = turbine;
-}
-OffInstruction.prototype.execute = function() {
- this.turbine.off();
-};
-
-function SpeedUpInstruction(turbine) {
- this.turbine = turbine;
-}
-SpeedUpInstruction.prototype.execute = function() {
- this.turbine.speedUp();
-};
-
-function SpeedDownInstruction(turbine) {
- this.turbine = turbine;
-}
-SpeedDownInstruction.prototype.execute = function() {
- this.turbine.speedDown();
-};
-
-module.exports = [Cockpit, Turbine, OnInstruction, OffInstruction, SpeedUpInstruction, SpeedDownInstruction];`,
- codeES6: `class Cockpit {
- constructor(instruction) {
- this.instruction = instruction;
- }
- execute() {
- this.instruction.execute();
- }
-}
-
-class Turbine {
- constructor() {
- this.state = false;
- }
- on() {
- this.state = true;
- }
- off() {
- this.state = false;
- }
-}
-
-class OnInstruction {
- constructor(turbine) {
- this.turbine = turbine;
- }
- execute() {
- this.turbine.on();
- }
-}
-
-class OffInstruction {
- constructor(turbine) {
- this.turbine = turbine;
- }
- execute() {
- this.turbine.off();
- }
-}
-
-export { Cockpit, Turbine, OnInstruction, OffInstruction };`
- },
- /*
- * Interpreter
- */
- {
- id: 'interpteter',
- name: 'Interpreter',
- type: 'behavioral',
- hint: 'implements a specialized language',
- codeES5: `function Sum(left, right) {
- this.left = left;
- this.right = right;
-}
-
-Sum.prototype.pattern = function() {
- return this.left.pattern() + this.right.pattern();
-};
-
-function Min(left, right) {
- this.left = left;
- this.right = right;
-}
-
-Min.prototype.pattern = function() {
- return this.left.pattern() - this.right.pattern();
-};
-
-function Num(val) {
- this.val = val;
-}
-
-Num.prototype.pattern = function() {
- return this.val;
-};
-
-module.exports = [Num, Min, Sum];`,
- codeES6: `class Sum {
- constructor(left, right) {
- this.left = left;
- this.right = right;
- }
-
- pattern() {
- return this.left.pattern() + this.right.pattern();
- }
-}
-
-class Min {
- constructor(left, right) {
- this.left = left;
- this.right = right;
- }
-
- pattern() {
- return this.left.pattern() - this.right.pattern();
- }
-}
-
-class Num {
- constructor(val) {
- this.val = val;
- }
-
- pattern() {
- return this.val;
- }
-}
-
-export { Num, Min, Sum };`
- },
- /*
- * Iterator
- */
- {
- id: 'iterator',
- name: 'Iterator',
- type: 'behavioral',
- hint:
- 'accesses the elements of an object sequentially without exposing its underlying representation',
- codeES5: `function Pattern(el) {
- this.index = 0;
- this.elements = el;
-}
-
-Pattern.prototype = {
- next: function() {
- return this.elements[this.index++];
- },
- hasNext: function() {
- return this.index < this.elements.length;
- }
-};
-
-module.exports = Pattern;`,
- codeES6: `class Pattern {
- constructor(el) {
- this.index = 0;
- this.elements = el;
- }
-
- next() {
- return this.elements[this.index++];
- }
-
- hasNext() {
- return this.index < this.elements.length;
- }
-}
-
-export default Pattern;`
- },
- /*
- * Mediator
- */
- {
- id: 'mediator',
- name: 'Mediator',
- type: 'behavioral',
- hint:
- 'allows loose coupling between classes by being the only class that has detailed knowledge of their methods',
- codeES5: `function TrafficTower() {
- this.airplanes = [];
-}
-
-TrafficTower.prototype.requestPositions = function() {
- return this.airplanes.map(function(airplane) {
- return airplane.position;
- });
-};
-
-function Airplane(position, trafficTower) {
- this.position = position;
- this.trafficTower = trafficTower;
- this.trafficTower.airplanes.push(this);
-}
-
-Airplane.prototype.requestPositions = function() {
- return this.trafficTower.requestPositions();
-};
-
-module.exports = [TrafficTower, Airplane];`,
- codeES6: `class TrafficTower {
- constructor() {
- this.airplanes = [];
- }
-
- requestPositions() {
- return this.airplanes.map(airplane => {
- return airplane.position;
- });
- }
-}
-
-class Airplane {
- constructor(position, trafficTower) {
- this.position = position;
- this.trafficTower = trafficTower;
- this.trafficTower.airplanes.push(this);
- }
-
- requestPositions() {
- return this.trafficTower.requestPositions();
- }
-}
-
-export { TrafficTower, Airplane };`
- },
- /*
- * Memento
- */
- {
- id: 'memento',
- name: 'Memento',
- type: 'behavioral',
- hint: 'provides the ability to restore an object to its previous state',
- codeES5: `function Pattern(value) {
- this.value = value;
-}
-
-var originator = {
- store: function(val) {
- return new Pattern(val);
- },
- restore: function(pattern) {
- return pattern.value;
- }
-};
-
-function Caretaker() {
- this.values = [];
-}
-
-Caretaker.prototype.addPattern = function(pattern) {
- this.values.push(pattern);
-};
-
-Caretaker.prototype.getPattern = function(index) {
- return this.values[index];
-};
-
-module.exports = [originator, Caretaker];`,
- codeES6: `class Pattern {
- constructor(value) {
- this.value = value;
- }
-}
-
-const originator = {
- store: function(val) {
- return new Pattern(val);
- },
- restore: function(pattern) {
- return pattern.value;
- }
-};
-
-class Caretaker {
- constructor() {
- this.values = [];
- }
-
- addPattern(pattern) {
- this.values.push(pattern);
- }
-
- getPattern(index) {
- return this.values[index];
- }
-}
-
-export { originator, Caretaker };`
- },
- /*
- * Observer
- */
- {
- id: 'observer',
- name: 'Observer',
- type: 'behavioral',
- hint:
- 'is a publish/subscribe pattern which allows a number of observer objects to see an event',
- codeES5: `function Product() {
- this.price = 0;
- this.actions = [];
-}
-
-Product.prototype.setBasePrice = function(val) {
- this.price = val;
- this.notifyAll();
-};
-
-Product.prototype.register = function(observer) {
- this.actions.push(observer);
-};
-
-Product.prototype.unregister = function(observer) {
- this.actions.remove.filter(function(el) {
- return el !== observer;
- });
-};
-
-Product.prototype.notifyAll = function() {
- return this.actions.forEach(
- function(el) {
- el.update(this);
- }.bind(this)
- );
-};
-
-var fees = {
- update: function(product) {
- product.price = product.price * 1.2;
- }
-};
-
-var proft = {
- update: function(product) {
- product.price = product.price * 2;
- }
-};
-
-module.exports = [Product, fees, proft];`,
- codeES6: `class Product {
- constructor() {
- this.price = 0;
- this.actions = [];
- }
-
- setBasePrice(val) {
- this.price = val;
- this.notifyAll();
- }
-
- register(observer) {
- this.actions.push(observer);
- }
-
- unregister(observer) {
- this.actions.remove.filter(function(el) {
- return el !== observer;
- });
- }
-
- notifyAll() {
- return this.actions.forEach(
- function(el) {
- el.update(this);
- }.bind(this)
- );
- }
-}
-
-class fees {
- update(product) {
- product.price = product.price * 1.2;
- }
-}
-
-class proft {
- update(product) {
- product.price = product.price * 2;
- }
-}
-
-export { Product, fees, proft };`
- },
- /*
- * State
- */
- {
- id: 'state',
- name: 'State',
- type: 'behavioral',
- hint: 'allows an object to alter its behavior when its internal state changes',
- codeES5: `function Order() {
- this.pattern = new WaitingForPayment();
-
- this.nextPattern = function() {
- this.pattern = this.pattern.next();
- };
-}
-
-function WaitingForPayment() {
- this.name = 'waitingForPayment';
- this.next = function() {
- return new Shipping();
- };
-}
-
-function Shipping() {
- this.name = 'shipping';
- this.next = function() {
- return new Delivered();
- };
-}
-
-function Delivered() {
- this.name = 'delivered';
- this.next = function() {
- return this;
- };
-}
-
-module.exports = Order;`,
- codeES6: `class OrderStatus {
- constructor(name, nextStatus) {
- this.name = name;
- this.nextStatus = nextStatus;
- }
-
- next() {
- return new this.nextStatus();
- }
-}
-
-class WaitingForPayment extends OrderStatus {
- constructor() {
- super('waitingForPayment', Shipping);
- }
-}
-
-class Shipping extends OrderStatus {
- constructor() {
- super('shipping', Delivered);
- }
-}
-
-class Delivered extends OrderStatus {
- constructor() {
- super('delivered', Delivered);
- }
-}
-
-class Order {
- constructor() {
- this.pattern = new WaitingForPayment();
- }
-
- nextPattern() {
- this.pattern = this.pattern.next();
- }
-}
-
-export default Order;`
- },
- /*
- * Strategy
- */
- {
- id: 'strategy',
- name: 'Strategy',
- type: 'behavioral',
- hint: 'allows one of a family of algorithms to be selected on-the-fly at runtime',
- codeES5: `function ShoppingCart(discount) {
- this.discount = discount;
- this.amount = 0;
-}
-
-ShoppingCart.prototype.setAmount = function(amount) {
- this.amount = amount;
-};
-
-ShoppingCart.prototype.checkout = function() {
- return this.discount(this.amount);
-};
-
-function guestPattern(amount) {
- return amount;
-}
-
-function regularPattern(amount) {
- return amount * 0.9;
-}
-
-function premiumPattern(amount) {
- return amount * 0.8;
-}
-
-module.exports = [ShoppingCart, guestPattern, regularPattern, premiumPattern];`,
- codeES6: `class ShoppingCart {
- constructor(discount) {
- this.discount = discount;
- this.amount = 0;
- }
-
- checkout() {
- return this.discount(this.amount);
- }
-
- setAmount(amount) {
- this.amount = amount;
- }
-}
-
-function guestPattern(amount) {
- return amount;
-}
-
-function regularPattern(amount) {
- return amount * 0.9;
-}
-
-function premiumPattern(amount) {
- return amount * 0.8;
-}
-
-export { ShoppingCart, guestPattern, regularPattern, premiumPattern };`
- },
- /*
- * Template
- */
- {
- id: 'template',
- name: 'Template',
- type: 'behavioral',
- hint:
- 'defines the skeleton of an algorithm as an abstract class, allowing its subclasses to provide concrete behavior',
- codeES5: `function Tax() {}
-
-Tax.prototype.calc = function(value) {
- if (value >= 1000) value = this.overThousand(value);
-
- return this.complementaryFee(value);
-};
-
-Tax.prototype.complementaryFee = function(value) {
- return value + 10;
-};
-
-function Tax1() {}
-Tax1.prototype = Object.create(Tax.prototype);
-
-Tax1.prototype.overThousand = function(value) {
- return value * 1.1;
-};
-
-function Tax2() {}
-Tax2.prototype = Object.create(Tax.prototype);
-
-Tax2.prototype.overThousand = function(value) {
- return value * 1.2;
-};
-
-module.exports = [Tax1, Tax2];`,
- codeES6: `class Tax {
- calc(value) {
- if (value >= 1000) value = this.overThousand(value);
-
- return this.complementaryFee(value);
- }
-
- complementaryFee(value) {
- return value + 10;
- }
-}
-
-class Tax1 extends Tax {
- constructor() {
- super();
- }
- overThousand(value) {
- return value * 1.1;
- }
-}
-
-class Tax2 extends Tax {
- constructor() {
- super();
- }
- overThousand(value) {
- return value * 1.2;
- }
-}
-
-export { Tax1, Tax2 };`
- },
- /*
- * Visitor
- */
- {
- id: 'visitor',
- name: 'Visitor',
- type: 'behavioral',
- hint:
- 'separates an algorithm from an object structure by moving the hierarchy of methods into one object',
- codeES5: `function bonusPattern(employee) {
- if (employee instanceof Manager) employee.bonus = employee.salary * 2;
- if (employee instanceof Developer) employee.bonus = employee.salary;
-}
-
-function Employee() {
- this.bonus = 0;
-}
-
-Employee.prototype.accept = function(item) {
- item(this);
-};
-
-function Manager(salary) {
- this.salary = salary;
-}
-
-Manager.prototype = Object.create(Employee.prototype);
-
-function Developer(salary) {
- this.salary = salary;
-}
-
-Developer.prototype = Object.create(Employee.prototype);
-
-module.exports = [Developer, Manager, bonusPattern];`,
- codeES6: `function bonusPattern(employee) {
- if (employee instanceof Manager) employee.bonus = employee.salary * 2;
- if (employee instanceof Developer) employee.bonus = employee.salary;
-}
-
-class Employee {
- constructor(salary) {
- this.bonus = 0;
- this.salary = salary;
- }
-
- accept(item) {
- item(this);
- }
-}
-
-class Manager extends Employee {
- constructor(salary) {
- super(salary);
- }
-}
-
-class Developer extends Employee {
- constructor(salary) {
- super(salary);
- }
-}
-
-export { Developer, Manager, bonusPattern };`
- }
+const patterns = [
+ ABSTRACT_FACTORY,
+ BUILDER,
+ FACTORY,
+ PROTOTYPE,
+ SINGLETON,
+
+ ADAPTER,
+ BRIDGE,
+ COMPOSITE,
+ DECORATOR,
+ FACADE,
+ FLYWEIGHT,
+ PROXY,
+
+ CHAIN_OF_RESPONSIBILITY,
+ COMMAND,
+ INTERPRETER,
+ ITERATOR,
+ MEDIATOR,
+ MEMENTO,
+ OBSERVER,
+ STATE,
+ STRATEGY,
+ TEMPLATE,
+ VISITOR
];
for (let i = patterns.length - 1; i > 0; i--) {
diff --git a/src/static/patterns/structural_adapter.js b/src/static/patterns/structural_adapter.js
new file mode 100644
index 0000000..87cfc25
--- /dev/null
+++ b/src/static/patterns/structural_adapter.js
@@ -0,0 +1,65 @@
+const ADAPTER = {
+ id: 'adapter',
+ name: 'Adapter',
+ type: 'structural',
+ hint: `allows classes with incompatible interfaces to work together by wrapping
+ its own interface around that of an already existing class`,
+ codeES5: `function Soldier(lvl) {
+this.lvl = lvl;
+}
+
+Soldier.prototype.attack = function() {
+return this.lvl * 1;
+};
+
+function Jedi(lvl) {
+this.lvl = lvl;
+}
+
+Jedi.prototype.attackWithSaber = function() {
+return this.lvl * 100;
+};
+
+function JediPattern(jedi) {
+this.jedi = jedi;
+}
+
+JediPattern.prototype.attack = function() {
+return this.jedi.attackWithSaber();
+};
+
+module.exports = [Soldier, Jedi, JediPattern];`,
+ codeES6: `class Soldier {
+constructor(level) {
+ this.level = level;
+}
+
+attack() {
+ return this.level * 1;
+}
+}
+
+class Jedi {
+constructor(level) {
+ this.level = level;
+}
+
+attackWithSaber() {
+ return this.level * 100;
+}
+}
+
+class JediPattern {
+constructor(jedi) {
+ this.jedi = jedi;
+}
+
+attack() {
+ return this.jedi.attackWithSaber();
+}
+}
+
+export { Soldier, Jedi, JediPattern };`
+};
+
+export default ADAPTER;
diff --git a/src/static/patterns/structural_bridge.js b/src/static/patterns/structural_bridge.js
new file mode 100644
index 0000000..9268f97
--- /dev/null
+++ b/src/static/patterns/structural_bridge.js
@@ -0,0 +1,79 @@
+const BRIDGE = {
+ id: 'bridge',
+ name: 'Bridge',
+ type: 'structural',
+ hint: 'decouples an abstraction from its implementation so that the two can vary independently',
+ codeES5: `function EpsonPrinter(ink) {
+this.ink = ink();
+}
+EpsonPrinter.prototype.print = function() {
+return 'Printer: Epson, Ink: ' + this.ink;
+};
+
+function HPprinter(ink) {
+this.ink = ink();
+}
+HPprinter.prototype.print = function() {
+return 'Printer: HP, Ink: ' + this.ink;
+};
+
+function acrylicInk() {
+return 'acrylic-based';
+}
+
+function alcoholInk() {
+return 'alcohol-based';
+}
+
+module.exports = [EpsonPrinter, HPprinter, acrylicInk, alcoholInk];`,
+ codeES6: `class Printer {
+constructor(ink) {
+ this.ink = ink;
+}
+}
+
+class EpsonPrinter extends Printer {
+constructor(ink) {
+ super(ink);
+}
+
+print() {
+ return 'Printer: Epson, Ink: ' + this.ink.get();
+}
+}
+
+class HPprinter extends Printer {
+constructor(ink) {
+ super(ink);
+}
+
+print() {
+ return 'Printer: HP, Ink: ' + this.ink.get();
+}
+}
+
+class Ink {
+constructor(type) {
+ this.type = type;
+}
+get() {
+ return this.type;
+}
+}
+
+class AcrylicInk extends Ink {
+constructor() {
+ super('acrylic-based');
+}
+}
+
+class AlcoholInk extends Ink {
+constructor() {
+ super('alcohol-based');
+}
+}
+
+export { EpsonPrinter, HPprinter, AcrylicInk, AlcoholInk };`
+};
+
+export default BRIDGE;
diff --git a/src/static/patterns/structural_composite.js b/src/static/patterns/structural_composite.js
new file mode 100644
index 0000000..9fad8bf
--- /dev/null
+++ b/src/static/patterns/structural_composite.js
@@ -0,0 +1,122 @@
+const COMPOSITE = {
+ id: 'composite',
+ name: 'Composite',
+ type: 'structural',
+ hint: 'composes zero-or-more similar objects so that they can be manipulated as one object',
+ codeES5: `function EquipmentPattern(name) {
+this.equipments = [];
+this.name = name;
+}
+
+EquipmentPattern.prototype.add = function(equipment) {
+this.equipments.push(equipment);
+};
+
+EquipmentPattern.prototype.getPrice = function() {
+return this.equipments
+ .map(function(equipment) {
+ return equipment.getPrice();
+ })
+ .reduce(function(a, b) {
+ return a + b;
+ });
+};
+
+function Equipment() {}
+
+Equipment.prototype.getPrice = function() {
+return this.price;
+};
+
+// -- leafs
+function FloppyDisk() {
+this.name = 'Floppy Disk';
+this.price = 70;
+}
+FloppyDisk.prototype = Object.create(Equipment.prototype);
+
+function HardDrive() {
+this.name = 'Hard Drive';
+this.price = 250;
+}
+HardDrive.prototype = Object.create(Equipment.prototype);
+
+function Memory() {
+this.name = '8gb memomry';
+this.price = 280;
+}
+Memory.prototype = Object.create(Equipment.prototype);
+
+module.exports = [EquipmentPattern, FloppyDisk, HardDrive, Memory];`,
+ codeES6: `//Equipment
+class Equipment {
+getPrice() {
+ return this.price || 0;
+}
+
+getName() {
+ return this.name;
+}
+
+setName(name) {
+ this.name = name;
+}
+}
+
+class Pattern extends Equipment {
+constructor() {
+ super();
+ this.equipments = [];
+}
+
+add(equipment) {
+ this.equipments.push(equipment);
+}
+
+getPrice() {
+ return this.equipments
+ .map(equipment => {
+ return equipment.getPrice();
+ })
+ .reduce((a, b) => {
+ return a + b;
+ });
+}
+}
+
+class Cabbinet extends Pattern {
+constructor() {
+ super();
+ this.setName('cabbinet');
+}
+}
+
+// --- leafs ---
+class FloppyDisk extends Equipment {
+constructor() {
+ super();
+ this.setName('Floppy Disk');
+ this.price = 70;
+}
+}
+
+class HardDrive extends Equipment {
+constructor() {
+ super();
+ this.setName('Hard Drive');
+ this.price = 250;
+}
+}
+
+class Memory extends Equipment {
+constructor() {
+ super();
+ this.setName('Memory');
+ this.price = 280;
+}
+}
+
+export { Cabbinet, FloppyDisk, HardDrive, Memory };`
+};
+
+export default COMPOSITE;
diff --git a/src/static/patterns/structural_decorator.js b/src/static/patterns/structural_decorator.js
new file mode 100644
index 0000000..10249dd
--- /dev/null
+++ b/src/static/patterns/structural_decorator.js
@@ -0,0 +1,85 @@
+const DECORATOR = {
+ id: 'decorator',
+ name: 'Decorator',
+ type: 'structural',
+ hint: 'dynamically adds/overrides behaviour in an existing method of an object',
+ codeES5: `function Pasta() {
+this.price = 0;
+}
+Pasta.prototype.getPrice = function() {
+return this.price;
+};
+
+function Penne() {
+this.price = 8;
+}
+Penne.prototype = Object.create(Pasta.prototype);
+
+function SaucePattern(pasta) {
+this.pasta = pasta;
+}
+
+SaucePattern.prototype.getPrice = function() {
+return this.pasta.getPrice() + 5;
+};
+
+function CheesePattern(pasta) {
+this.pasta = pasta;
+}
+
+CheesePattern.prototype.getPrice = function() {
+return this.pasta.getPrice() + 3;
+};
+
+module.exports = [Penne, SaucePattern, CheesePattern];`,
+ codeES6: `class Pasta {
+constructor() {
+ this.price = 0;
+}
+getPrice() {
+ return this.price;
+}
+}
+
+class Penne extends Pasta {
+constructor() {
+ super();
+ this.price = 8;
+}
+}
+
+class PastaPattern extends Pasta {
+constructor(pasta) {
+ super();
+ this.pasta = pasta;
+}
+
+getPrice() {
+ return this.pasta.getPrice();
+}
+}
+
+class SaucePattern extends PastaPattern {
+constructor(pasta) {
+ super(pasta);
+}
+
+getPrice() {
+ return super.getPrice() + 5;
+}
+}
+
+class CheesePattern extends PastaPattern {
+constructor(pasta) {
+ super(pasta);
+}
+
+getPrice() {
+ return super.getPrice() + 3;
+}
+}
+
+export { Penne, SaucePattern, CheesePattern };`
+};
+
+export default DECORATOR;
diff --git a/src/static/patterns/structural_facade.js b/src/static/patterns/structural_facade.js
new file mode 100644
index 0000000..40c1f84
--- /dev/null
+++ b/src/static/patterns/structural_facade.js
@@ -0,0 +1,64 @@
+const FACADE = {
+ id: 'facade',
+ name: 'Facade',
+ type: 'structural',
+ hint: 'provides a simplified interface to a large body of code',
+ codeES5: `var shopPattern = {
+calc: function(price) {
+ price = discount(price);
+ price = fees(price);
+ price += shipping();
+ return price;
+}
+};
+
+function discount(value) {
+return value * 0.9;
+}
+
+function shipping() {
+return 5;
+}
+
+function fees(value) {
+return value * 1.05;
+}
+
+module.exports = shopPattern;`,
+ codeES6: `class ShopPattern {
+constructor() {
+ this.discount = new Discount();
+ this.shipping = new Shipping();
+ this.fees = new Fees();
+}
+
+calc(price) {
+ price = this.discount.calc(price);
+ price = this.fees.calc(price);
+ price += this.shipping.calc();
+ return price;
+}
+}
+
+class Discount {
+calc(value) {
+ return value * 0.9;
+}
+}
+
+class Shipping {
+calc() {
+ return 5;
+}
+}
+
+class Fees {
+calc(value) {
+ return value * 1.05;
+}
+}
+
+export default ShopPattern;`
+};
+
+export default FACADE;
diff --git a/src/static/patterns/structural_flyweight.js b/src/static/patterns/structural_flyweight.js
new file mode 100644
index 0000000..3adb6c6
--- /dev/null
+++ b/src/static/patterns/structural_flyweight.js
@@ -0,0 +1,43 @@
+const FLYWEIGHT = {
+ id: 'flyweight',
+ name: 'Flyweight',
+ type: 'structural',
+ hint: 'reduces the cost of creating and manipulating a large number of similar objects',
+ codeES5: `function Color(name) {
+this.name = name;
+}
+
+var colorCreator = {
+colors: {},
+create: function(name) {
+ var color = this.colors[name];
+ if (color) return color;
+
+ this.colors[name] = new Color(name);
+ return this.colors[name];
+}
+};
+
+module.exports = colorCreator;`,
+ codeES6: `class Color {
+constructor(name) {
+ this.name = name;
+}
+}
+
+class colorCreator {
+constructor(name) {
+ this.colors = {};
+}
+create(name) {
+ let color = this.colors[name];
+ if (color) return color;
+ this.colors[name] = new Color(name);
+ return this.colors[name];
+}
+}
+
+export { colorCreator };`
+};
+
+export default FLYWEIGHT;
diff --git a/src/static/patterns/structural_proxy.js b/src/static/patterns/structural_proxy.js
new file mode 100644
index 0000000..91b76e2
--- /dev/null
+++ b/src/static/patterns/structural_proxy.js
@@ -0,0 +1,50 @@
+const PROXY = {
+ id: 'proxy',
+ name: 'Proxy',
+ type: 'structural',
+ hint:
+ 'provides a placeholder for another object to control access, reduce cost, and reduce complexity',
+ codeES5: `function Car() {
+this.drive = function() {
+ return 'driving';
+};
+}
+
+function CarPattern(driver) {
+this.driver = driver;
+this.drive = function() {
+ if (driver.age < 18) return 'too young to drive';
+ return new Car().drive();
+};
+}
+
+function Driver(age) {
+this.age = age;
+}
+
+module.exports = [Car, CarPattern, Driver];`,
+ codeES6: `class Car {
+drive() {
+ return 'driving';
+}
+}
+
+class CarPattern {
+constructor(driver) {
+ this.driver = driver;
+}
+drive() {
+ return this.driver.age < 18 ? 'too young to drive' : new Car().drive();
+}
+}
+
+class Driver {
+constructor(age) {
+ this.age = age;
+}
+}
+
+export { Car, CarPattern, Driver };`
+};
+
+export default PROXY;