├── factory ├── laptop.js ├── tablet.js ├── gadgetFactory.js └── index.js ├── pubsub ├── index.js ├── moduleA.js ├── moduleB.js └── pubsub.js ├── package.json ├── LICENSE ├── .gitignore └── README.md /factory/laptop.js: -------------------------------------------------------------------------------- 1 | const Laptop = function({ ram, ssd, name }) { 2 | this.ram = ram || 0; 3 | this.ssd = ssd || 0; 4 | this.name = name; 5 | }; 6 | 7 | module.exports = Laptop; 8 | -------------------------------------------------------------------------------- /pubsub/index.js: -------------------------------------------------------------------------------- 1 | const moduleA = require("./moduleA"); 2 | const moduleB = require("./moduleB"); 3 | 4 | // We use moduleA's publishEvent() method 5 | moduleA.publishEvent(); 6 | moduleA.publishEvent(); 7 | -------------------------------------------------------------------------------- /factory/tablet.js: -------------------------------------------------------------------------------- 1 | const Tablet = function({ ram, hdd, name, network }) { 2 | this.ram = ram || 0; 3 | this.hdd = hdd || 0; 4 | this.network = network || "3G"; 5 | this.name = name; 6 | }; 7 | 8 | module.exports = Tablet; 9 | -------------------------------------------------------------------------------- /pubsub/moduleA.js: -------------------------------------------------------------------------------- 1 | const pubSub = require("./pubsub"); 2 | 3 | module.exports = { 4 | publishEvent() { 5 | const data = { 6 | msg: "TOP SECRET DATA" 7 | }; 8 | 9 | pubSub.publish("anEvent", data); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /pubsub/moduleB.js: -------------------------------------------------------------------------------- 1 | const pubSub = require("./pubsub"); 2 | let subscription; 3 | 4 | subscription = pubSub.subscribe("anEvent", data => { 5 | console.log(`"anEvent", was published with this data: "${data.msg}"`); 6 | subscription.unsubscribe(); 7 | }); 8 | -------------------------------------------------------------------------------- /factory/gadgetFactory.js: -------------------------------------------------------------------------------- 1 | const Laptop = require("./laptop"); 2 | const Tablet = require("./tablet"); 3 | 4 | const gadget = { Laptop, Tablet }; 5 | 6 | module.exports = { 7 | createGadget(type, attributes) { 8 | const GadgetType = gadget[type]; 9 | return new GadgetType(attributes); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /factory/index.js: -------------------------------------------------------------------------------- 1 | const gadgetFactory = require("./gadgetFactory"); 2 | 3 | const myLaptop = gadgetFactory.createGadget("Laptop", { 4 | ram: 8, 5 | ssd: 256, 6 | name: "Bab's MacBook Pro" 7 | }); 8 | 9 | const myTablet = gadgetFactory.createGadget("Tablet", { 10 | ram: 4, 11 | hdd: 128, 12 | network: "4G", 13 | name: "Bab's iPad" 14 | }); 15 | 16 | console.log(myLaptop); 17 | console.log(myTablet); 18 | -------------------------------------------------------------------------------- /pubsub/pubsub.js: -------------------------------------------------------------------------------- 1 | let subscribers = {}; 2 | 3 | module.exports = { 4 | publish(event, data) { 5 | if (!subscribers[event]) return; 6 | 7 | subscribers[event].forEach(subscriberCallback => subscriberCallback(data)); 8 | }, 9 | subscribe(event, callback) { 10 | let index; 11 | 12 | if (!subscribers[event]) { 13 | subscribers[event] = []; 14 | } 15 | 16 | index = subscribers[event].push(callback) - 1; 17 | 18 | return { 19 | unsubscribe() { 20 | subscribers[event].splice(index, 1); 21 | } 22 | }; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-design-patterns", 3 | "version": "1.0.0", 4 | "description": "A collection of examples of various design patterns written in Javascript", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node ./$PATTERN/index.js", 8 | "start-dev": "nodemon ./$PATTERN/index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/babzcraig/javascript-design-patterns.git" 13 | }, 14 | "keywords": [ 15 | "Javascript" 16 | ], 17 | "author": "Babs Craig", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/babzcraig/javascript-design-patterns/issues" 21 | }, 22 | "homepage": "https://github.com/babzcraig/javascript-design-patterns#readme", 23 | "dependencies": { 24 | "nodemon": "^1.18.4" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Babs Craig 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design Patterns In Javascript 2 | 3 | Design Patterns can help us write more efficient, maintainable and clearer code. They're time tested solutions to common problems in software design. I've recently taken a closer interest in design patterns and decided to document the types of design patterns I've come across, as they apply specifically to Javascript. A lot of the examples out there are pre-ES2015 and I thought it would be nice to redo them in more mordern syntax. 4 | 5 | Please note that not all examples have been converted fully to ES6. It is a work in progress and I'll be refactoring the code as I progress. 6 | 7 | Each folder contains a small app which illustrates a design pattern. The folders are named after the design patterns they illustrate. The samples are simplistic and intended only to illustrate the features of each pattern. 8 | 9 | ## Walkthrough 10 | 11 | You can find articles walking through each design pattern on my Medium. Currently the first article on the **Factory Pattern** is up. As I add more articles, I'll list the links below: 12 | 13 | ### Creational Design Patterns 14 | 15 | - Factory Pattern - [Link](https://medium.com/@thebabscraig/javascript-design-patterns-part-1-the-factory-pattern-5f135e881192) 16 | 17 | ### Behavioural Design Patterns 18 | 19 | - Publisher/Subscriber Pattern - [Link](https://medium.com/@thebabscraig/javascript-design-patterns-part-2-the-publisher-subscriber-pattern-8fe07e157213) 20 | - Strategy Pattern - TBD 21 | - Observer Pattern - TBD 22 | - Chain of Responsibility Pattern - TBD 23 | - Mediator Pattern - TBD 24 | - Iterator Pattern - TBD 25 | 26 | ### Structural Design Patterns 27 | 28 | - Facade Pattern - TBD 29 | - Decorator Pattern - TBD 30 | - Adapter Pattern - TBD 31 | - Composite Pattern - TBD 32 | - Proxy Pattern - TBD 33 | 34 | ## To run the files: 35 | 36 | 1. `git clone` the repo to a local folder. 37 | 2. Run `npm install` to install the node_modules (this is mainly for nodemon so we can run node with autorefresh enabled) 38 | 3. There are two commands, `npm start` and `npm run start-dev`. 39 | 4. To run the examples, pass in the folder name for the specific design pattern as an npm argument. For example, to run the "**factory**" design pattern, you would enter the command `PATTERN=factory npm run start-dev` in your temrinal. 40 | 5. The folder names correspond to the design pattern names. 41 | 42 | --- 43 | 44 | This is still a work in progress and I'll be adding more design patterns 45 | 46 | If you have any suggestions or would like to contribute in any way, please feel free to open an issue or make a PR. 47 | --------------------------------------------------------------------------------