diff --git a/src/data/patterns.js b/src/data/patterns.js index d851f85..3895c07 100644 --- a/src/data/patterns.js +++ b/src/data/patterns.js @@ -3,18 +3,20 @@ 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 battleDroidFactory; - return pilotDroidFactory; + if (kind === 'battle') return battleDroidPattern; + return pilotDroidPattern; } -function battleDroidFactory() { +function battleDroidPattern() { return new B1(); } -function pilotDroidFactory() { +function pilotDroidPattern() { return new Rx24(); } @@ -30,15 +32,15 @@ Rx24.prototype.info = function() { module.exports = droidProducer;`, codeES6: `function droidProducer(kind) { - if (kind === 'battle') return battleDroidFactory; - return pilotDroidFactory; + if (kind === 'battle') return battleDroidPattern; + return pilotDroidPattern; } -function battleDroidFactory() { +function battleDroidPattern() { return new B1(); } -function pilotDroidFactory() { +function pilotDroidPattern() { return new Rx24(); } @@ -60,15 +62,17 @@ 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 RequestBuilder() { +function RequestPattern() { this.request = new Request(); this.forUrl = function(url) { @@ -91,7 +95,7 @@ function RequestBuilder() { }; } -module.exports = RequestBuilder;`, +module.exports = RequestPattern;`, codeES6: `class Request { constructor() { this.url = ''; @@ -100,7 +104,7 @@ module.exports = RequestBuilder;`, } } -class RequestBuilder { +class RequestPattern { constructor() { this.request = new Request(); } @@ -125,34 +129,36 @@ class RequestBuilder { } } -export default RequestBuilder;` +export default RequestPattern;` }, /* * Factory */ { + id: 'factory', name: 'Factory', type: 'creational', - codeES5: `function bmwFactory(type) { - if (type === 'X5') return new Bmw(type, 108000, 300); - if (type === 'X6') return new Bmw(type, 111000, 320); + 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 Bmw(model, price, maxSpeed) { +function Tesla(model, price, maxSpeed) { this.model = model; this.price = price; this.maxSpeed = maxSpeed; } -module.exports = bmwFactory;`, - codeES6: `class BmwFactory { +module.exports = teslaPattern;`, + codeES6: `class TeslaPattern { create(type) { - if (type === 'X5') return new Bmw(type, 108000, 300); - if (type === 'X6') return new Bmw(type, 111000, 320); + if (type === 'ModelX') return new Tesla(type, 108000, 300); + if (type === 'ModelS') return new Tesla(type, 111000, 320); } } -class Bmw { +class Tesla { constructor(model, price, maxSpeed) { this.model = model; this.price = price; @@ -160,14 +166,16 @@ class Bmw { } } -export default BmwFactory;` +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; @@ -195,8 +203,10 @@ 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; @@ -222,8 +232,11 @@ 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; } @@ -240,15 +253,15 @@ Jedi.prototype.attackWithSaber = function() { return this.lvl * 100; }; -function JediAdapter(jedi) { +function JediPattern(jedi) { this.jedi = jedi; } -JediAdapter.prototype.attack = function() { +JediPattern.prototype.attack = function() { return this.jedi.attackWithSaber(); }; -module.exports = [Soldier, Jedi, JediAdapter];`, +module.exports = [Soldier, Jedi, JediPattern];`, codeES6: `class Soldier { constructor(level) { this.level = level; @@ -269,7 +282,7 @@ class Jedi { } } -class JediAdapter { +class JediPattern { constructor(jedi) { this.jedi = jedi; } @@ -279,14 +292,16 @@ class JediAdapter { } } -export { Soldier, Jedi, JediAdapter };` +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(); } @@ -363,19 +378,20 @@ export { EpsonPrinter, HPprinter, AcrylicInk, AlcoholInk };` * Composite */ { + id: 'composite', name: 'Composite', type: 'structural', - codeES5: `// composition -function EquipmentComposition(name) { + 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; } -EquipmentComposition.prototype.add = function(equipment) { +EquipmentPattern.prototype.add = function(equipment) { this.equipments.push(equipment); }; -EquipmentComposition.prototype.getPrice = function() { +EquipmentPattern.prototype.getPrice = function() { return this.equipments .map(function(equipment) { return equipment.getPrice(); @@ -410,7 +426,7 @@ function Memory() { } Memory.prototype = Object.create(Equipment.prototype); -module.exports = [EquipmentComposition, FloppyDisk, HardDrive, Memory];`, +module.exports = [EquipmentPattern, FloppyDisk, HardDrive, Memory];`, codeES6: `//Equipment class Equipment { getPrice() { @@ -426,8 +442,7 @@ class Equipment { } } -// --- composite --- -class Composite extends Equipment { +class Pattern extends Equipment { constructor() { super(); this.equipments = []; @@ -448,7 +463,7 @@ class Composite extends Equipment { } } -class Cabbinet extends Composite { +class Cabbinet extends Pattern { constructor() { super(); this.setName('cabbinet'); @@ -486,8 +501,10 @@ 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; } @@ -500,23 +517,23 @@ function Penne() { } Penne.prototype = Object.create(Pasta.prototype); -function SauceDecorator(pasta) { +function SaucePattern(pasta) { this.pasta = pasta; } -SauceDecorator.prototype.getPrice = function() { +SaucePattern.prototype.getPrice = function() { return this.pasta.getPrice() + 5; }; -function CheeseDecorator(pasta) { +function CheesePattern(pasta) { this.pasta = pasta; } -CheeseDecorator.prototype.getPrice = function() { +CheesePattern.prototype.getPrice = function() { return this.pasta.getPrice() + 3; }; -module.exports = [Penne, SauceDecorator, CheeseDecorator];`, +module.exports = [Penne, SaucePattern, CheesePattern];`, codeES6: `class Pasta { constructor() { this.price = 0; @@ -533,7 +550,7 @@ class Penne extends Pasta { } } -class PastaDecorator extends Pasta { +class PastaPattern extends Pasta { constructor(pasta) { super(); this.pasta = pasta; @@ -544,7 +561,7 @@ class PastaDecorator extends Pasta { } } -class SauceDecorator extends PastaDecorator { +class SaucePattern extends PastaPattern { constructor(pasta) { super(pasta); } @@ -554,7 +571,7 @@ class SauceDecorator extends PastaDecorator { } } -class CheeseDecorator extends PastaDecorator { +class CheesePattern extends PastaPattern { constructor(pasta) { super(pasta); } @@ -564,15 +581,17 @@ class CheeseDecorator extends PastaDecorator { } } -export { Penne, SauceDecorator, CheeseDecorator };` +export { Penne, SaucePattern, CheesePattern };` }, /* * Facade */ { + id: 'facade', name: 'Facade', type: 'structural', - codeES5: `var shopFacade = { + hint: 'provides a simplified interface to a large body of code', + codeES5: `var shopPattern = { calc: function(price) { price = discount(price); price = fees(price); @@ -593,8 +612,8 @@ function fees(value) { return value * 1.05; } -module.exports = shopFacade;`, - codeES6: `class ShopFacade { +module.exports = shopPattern;`, + codeES6: `class ShopPattern { constructor() { this.discount = new Discount(); this.shipping = new Shipping(); @@ -627,19 +646,21 @@ class Fees { } } -export default ShopFacade;` +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 colorFactory = { +var colorCreator = { colors: {}, create: function(name) { var color = this.colors[name]; @@ -650,14 +671,14 @@ var colorFactory = { } }; -module.exports = colorFactory;`, +module.exports = colorCreator;`, codeES6: `class Color { constructor(name) { this.name = name; } } -class colorFactory { +class colorCreator { constructor(name) { this.colors = {}; } @@ -669,21 +690,24 @@ class colorFactory { } } -export { colorFactory };` +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 CarProxy(driver) { +function CarPattern(driver) { this.driver = driver; this.drive = function() { if (driver.age < 18) return 'too young to drive'; @@ -695,14 +719,14 @@ function Driver(age) { this.age = age; } -module.exports = [Car, CarProxy, Driver];`, +module.exports = [Car, CarPattern, Driver];`, codeES6: `class Car { drive() { return 'driving'; } } -class CarProxy { +class CarPattern { constructor(driver) { this.driver = driver; } @@ -717,14 +741,16 @@ class Driver { } } -export { Car, CarProxy, Driver };` +export { Car, CarPattern, Driver };` }, /* * Chain of Resp */ { - name: '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 = []; @@ -853,13 +879,15 @@ export { ShoppingCart, Discount };` * Command */ { + id: 'command', name: 'Command', type: 'behavioral', - codeES5: `function Cockpit(command) { - this.command = command; + hint: 'creates objects which encapsulate actions and parameters', + codeES5: `function Cockpit(instruction) { + this.instruction = instruction; } Cockpit.prototype.execute = function() { - this.command.execute(); + this.instruction.execute(); }; function Turbine() { @@ -889,41 +917,41 @@ Turbine.prototype.speedUp = function() { this.speed += 100; }; -function OnCommand(turbine) { +function OnInstruction(turbine) { this.turbine = turbine; } -OnCommand.prototype.execute = function() { +OnInstruction.prototype.execute = function() { this.turbine.on(); }; -function OffCommand(turbine) { +function OffInstruction(turbine) { this.turbine = turbine; } -OffCommand.prototype.execute = function() { +OffInstruction.prototype.execute = function() { this.turbine.off(); }; -function SpeedUpCommand(turbine) { +function SpeedUpInstruction(turbine) { this.turbine = turbine; } -SpeedUpCommand.prototype.execute = function() { +SpeedUpInstruction.prototype.execute = function() { this.turbine.speedUp(); }; -function SpeedDownCommand(turbine) { +function SpeedDownInstruction(turbine) { this.turbine = turbine; } -SpeedDownCommand.prototype.execute = function() { +SpeedDownInstruction.prototype.execute = function() { this.turbine.speedDown(); }; -module.exports = [Cockpit, Turbine, OnCommand, OffCommand, SpeedUpCommand, SpeedDownCommand];`, +module.exports = [Cockpit, Turbine, OnInstruction, OffInstruction, SpeedUpInstruction, SpeedDownInstruction];`, codeES6: `class Cockpit { - constructor(command) { - this.command = command; + constructor(instruction) { + this.instruction = instruction; } execute() { - this.command.execute(); + this.instruction.execute(); } } @@ -939,7 +967,7 @@ class Turbine { } } -class OnCommand { +class OnInstruction { constructor(turbine) { this.turbine = turbine; } @@ -948,7 +976,7 @@ class OnCommand { } } -class OffCommand { +class OffInstruction { constructor(turbine) { this.turbine = turbine; } @@ -957,21 +985,23 @@ class OffCommand { } } -export { Cockpit, Turbine, OnCommand, OffCommand };` +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.interpret = function() { - return this.left.interpret() + this.right.interpret(); +Sum.prototype.pattern = function() { + return this.left.pattern() + this.right.pattern(); }; function Min(left, right) { @@ -979,15 +1009,15 @@ function Min(left, right) { this.right = right; } -Min.prototype.interpret = function() { - return this.left.interpret() - this.right.interpret(); +Min.prototype.pattern = function() { + return this.left.pattern() - this.right.pattern(); }; function Num(val) { this.val = val; } -Num.prototype.interpret = function() { +Num.prototype.pattern = function() { return this.val; }; @@ -998,8 +1028,8 @@ module.exports = [Num, Min, Sum];`, this.right = right; } - interpret() { - return this.left.interpret() + this.right.interpret(); + pattern() { + return this.left.pattern() + this.right.pattern(); } } @@ -1009,8 +1039,8 @@ class Min { this.right = right; } - interpret() { - return this.left.interpret() - this.right.interpret(); + pattern() { + return this.left.pattern() - this.right.pattern(); } } @@ -1019,7 +1049,7 @@ class Num { this.val = val; } - interpret() { + pattern() { return this.val; } } @@ -1030,14 +1060,17 @@ export { Num, Min, Sum };` * Iterator */ { + id: 'iterator', name: 'Iterator', type: 'behavioral', - codeES5: `function Iterator(el) { + hint: + 'accesses the elements of an object sequentially without exposing its underlying representation', + codeES5: `function Pattern(el) { this.index = 0; this.elements = el; } -Iterator.prototype = { +Pattern.prototype = { next: function() { return this.elements[this.index++]; }, @@ -1046,8 +1079,8 @@ Iterator.prototype = { } }; -module.exports = Iterator;`, - codeES6: `class Iterator { +module.exports = Pattern;`, + codeES6: `class Pattern { constructor(el) { this.index = 0; this.elements = el; @@ -1062,14 +1095,17 @@ module.exports = Iterator;`, } } -export default Iterator;` +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 = []; } @@ -1121,18 +1157,20 @@ export { TrafficTower, Airplane };` * Memento */ { + id: 'memento', name: 'Memento', type: 'behavioral', - codeES5: `function Memento(value) { + 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 Memento(val); + return new Pattern(val); }, - restore: function(memento) { - return memento.value; + restore: function(pattern) { + return pattern.value; } }; @@ -1140,16 +1178,16 @@ function Caretaker() { this.values = []; } -Caretaker.prototype.addMemento = function(memento) { - this.values.push(memento); +Caretaker.prototype.addPattern = function(pattern) { + this.values.push(pattern); }; -Caretaker.prototype.getMemento = function(index) { +Caretaker.prototype.getPattern = function(index) { return this.values[index]; }; module.exports = [originator, Caretaker];`, - codeES6: `class Memento { + codeES6: `class Pattern { constructor(value) { this.value = value; } @@ -1157,10 +1195,10 @@ module.exports = [originator, Caretaker];`, const originator = { store: function(val) { - return new Memento(val); + return new Pattern(val); }, - restore: function(memento) { - return memento.value; + restore: function(pattern) { + return pattern.value; } }; @@ -1169,11 +1207,11 @@ class Caretaker { this.values = []; } - addMemento(memento) { - this.values.push(memento); + addPattern(pattern) { + this.values.push(pattern); } - getMemento(index) { + getPattern(index) { return this.values[index]; } } @@ -1184,8 +1222,11 @@ 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 = []; @@ -1275,13 +1316,15 @@ 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.state = new WaitingForPayment(); + this.pattern = new WaitingForPayment(); - this.nextState = function() { - this.state = this.state.next(); + this.nextPattern = function() { + this.pattern = this.pattern.next(); }; } @@ -1338,11 +1381,11 @@ class Delivered extends OrderStatus { class Order { constructor() { - this.state = new WaitingForPayment(); + this.pattern = new WaitingForPayment(); } - nextState() { - this.state = this.state.next(); + nextPattern() { + this.pattern = this.pattern.next(); } } @@ -1352,8 +1395,10 @@ 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; @@ -1367,19 +1412,19 @@ ShoppingCart.prototype.checkout = function() { return this.discount(this.amount); }; -function guestStrategy(amount) { +function guestPattern(amount) { return amount; } -function regularStrategy(amount) { +function regularPattern(amount) { return amount * 0.9; } -function premiumStrategy(amount) { +function premiumPattern(amount) { return amount * 0.8; } -module.exports = [ShoppingCart, guestStrategy, regularStrategy, premiumStrategy];`, +module.exports = [ShoppingCart, guestPattern, regularPattern, premiumPattern];`, codeES6: `class ShoppingCart { constructor(discount) { this.discount = discount; @@ -1395,26 +1440,29 @@ module.exports = [ShoppingCart, guestStrategy, regularStrategy, premiumStrategy] } } -function guestStrategy(amount) { +function guestPattern(amount) { return amount; } -function regularStrategy(amount) { +function regularPattern(amount) { return amount * 0.9; } -function premiumStrategy(amount) { +function premiumPattern(amount) { return amount * 0.8; } -export { ShoppingCart, guestStrategy, regularStrategy, premiumStrategy };` +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) { @@ -1478,9 +1526,12 @@ export { Tax1, Tax2 };` * Visitor */ { + id: 'visitor', name: 'Visitor', type: 'behavioral', - codeES5: `function bonusVisitor(employee) { + 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; } @@ -1489,8 +1540,8 @@ function Employee() { this.bonus = 0; } -Employee.prototype.accept = function(visitor) { - visitor(this); +Employee.prototype.accept = function(item) { + item(this); }; function Manager(salary) { @@ -1505,8 +1556,8 @@ function Developer(salary) { Developer.prototype = Object.create(Employee.prototype); -module.exports = [Developer, Manager, bonusVisitor];`, - codeES6: `function bonusVisitor(employee) { +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; } @@ -1517,8 +1568,8 @@ class Employee { this.salary = salary; } - accept(visitor) { - visitor(this); + accept(item) { + item(this); } } @@ -1534,7 +1585,7 @@ class Developer extends Employee { } } -export { Developer, Manager, bonusVisitor };` +export { Developer, Manager, bonusPattern };` } ];