├── .DS_Store ├── .gitignore ├── README.md ├── decorator.html ├── demo.html ├── doc ├── index.md ├── iterable-pattern.md ├── observer-pattern.md ├── pub-sub-pattern.md └── singleton-pattern.md ├── observer.html ├── pub-sub.html ├── singleton.html └── src ├── iterable.js ├── observer.js ├── publish-subscribe.js └── singleton.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slashhuang/design-patterns-tutorial/816d7b490f5416fc4c062b4e59438b39f1617a8c/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | node_modules 3 | test.js 4 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # design-patterns-tutorial 2 | 3 | ## Usage 使用 4 | 5 | ```bash 6 | 7 | git clone git@github.com:slashhuang/design-patterns-tutorial.git --depth=1 8 | 9 | cd design-patterns-tutorial 10 | 11 | ## open html file to check results 12 | 13 | ``` 14 | 15 | ### Demo 查看演示 16 | 17 | > 简易日志系统演示simple decorator log system 18 | 19 | [decorator设计模式](./decorator.html) 20 | 21 | > 简单的对象回调数组演示 simple observer array 22 | 23 | [observer设计模式](./observer.html) 24 | 25 | > 结合事件进行的订阅发布模式 pub-sub handler combined with DOM events 26 | 27 | [pub-sub设计模式](./pub-sub.html) 28 | 29 | > 内存管理之单例模式 memory saving strategy with singleton 30 | 31 | [singleton设计模式](./singleton.html) 32 | 33 | 34 | ## FAQ 35 | 36 | #### 1. 观察者模式与发布订阅模式如何区分? 37 | 38 | ##### observer vs pub/sub 39 | 40 | eg. $('input').change() 做三件事件 41 | 42 | - pub/sub ==> 是根据topic 比如click等来执行通知 43 | 44 | trigger('日志') trigger('发起请求) trigger(UI') 45 | 46 | - observer ==> 比如 redux.subscribe的api就是这样子 47 | 不会对事情做区分 48 | ['日志','发起请求','UI'].forEach(fn) 49 | 50 | #### 2. 单例模式应用场景 51 | 52 | dialog或者modal组件 53 | 54 | ```js 55 | 21 |
22 | result is ---- 0 23 |
24 | 35 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /doc/index.md: -------------------------------------------------------------------------------- 1 | ## design patterns 2 | 3 | ### introduction 4 | 5 | 1. publish subscribe pattern 订阅发布模式 6 | 2. observer pattern 观察者模式 7 | 3. decorator pattern 装饰者模式 8 | 4. singleton pattern 单例模式 9 | 5. iterable pattern 遍历模式 10 | 11 | ## js implementation 12 | -------------------------------------------------------------------------------- /doc/iterable-pattern.md: -------------------------------------------------------------------------------- 1 | # 可遍历模式 2 | 3 | ### reference 4 | [Iterator_pattern wiki](https://en.wikipedia.org/wiki/Iterator_pattern) -------------------------------------------------------------------------------- /doc/observer-pattern.md: -------------------------------------------------------------------------------- 1 | # observer pattern 2 | 3 | ### reference 4 | [wiki observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) 5 | 6 | The observer pattern is a software design pattern in which an object, 7 | called the subject, maintains a list of its dependents, called observers, 8 | and notifies them automatically of any state changes, usually by calling one of their methods. -------------------------------------------------------------------------------- /doc/pub-sub-pattern.md: -------------------------------------------------------------------------------- 1 | # observer pattern 2 | 3 | ### reference 4 | [wiki pub sub pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) 5 | 6 | -------------------------------------------------------------------------------- /doc/singleton-pattern.md: -------------------------------------------------------------------------------- 1 | # singleton pattern 2 | 3 | ### reference 4 | [wiki singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) 5 | 6 | In software engineering, the singleton pattern is a software design pattern 7 | that restricts the instantiation of a class to one object. 8 | This is useful when exactly one object is needed to coordinate actions across the system -------------------------------------------------------------------------------- /observer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 |
observer设计模式
18 | 19 |
20 | observer订阅发布举例子 21 |
22 | 加上数据 23 | 0 24 |
25 |
26 | 数据总和为 ---- 0 27 |
28 | 43 | 66 |
67 | 68 | -------------------------------------------------------------------------------- /pub-sub.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 38 | 39 | 40 |
pub-sub设计模式
41 |
42 | pub-sub订阅发布举例子 43 | 48 |
49 | 数据总和为 ---- 0 50 |
51 | 67 |
68 | 69 | -------------------------------------------------------------------------------- /singleton.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 |
singleton设计模式
14 |
15 |
singleton举例子
16 | 17 |
18 | result is ---- 0 19 |
20 | 37 | 45 | 46 |
47 | result is ---- 0 48 |
49 | 60 | 61 |
62 | 63 | -------------------------------------------------------------------------------- /src/iterable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 可遍历模式 3 | * ES6支持提供next方法的任何对象 4 | * https://en.wikipedia.org/wiki/Iterator_pattern#JavaScript 5 | * returns an object with two specific properties: 6 | * done and value 7 | */ 8 | // for ( var a = 1; a < 5; a++) { 9 | // console.log(a); 10 | // } 11 | // GeneratorFunction.next() 12 | // rxjs ==> observer.next(); 13 | // yield 14 | const iteratorP = (arr) => { 15 | let index = 0; 16 | return { 17 | next: () => { 18 | index++; 19 | if (index - 1 >= arr.length) { 20 | return { 21 | done: true, 22 | } 23 | } else { 24 | return { 25 | done: false, 26 | value: arr[index-1], 27 | } 28 | } 29 | } 30 | } 31 | }; 32 | const it1 = iteratorP([1,2,3,4,5]); 33 | console.log(it1.next()) 34 | console.log(it1.next()) 35 | console.log(it1.next()) 36 | console.log(it1.next()) 37 | console.log(it1.next()) 38 | console.log(it1.next()) 39 | 40 | function range(start, end) { 41 | return { 42 | [Symbol.iterator]() { //#A 43 | return this; 44 | }, 45 | next() { 46 | if(start < end) { 47 | return { value: start++, done:false }; //#B 48 | } 49 | return { done: true, value:end }; //#B 50 | } 51 | } 52 | } 53 | 54 | for(number of range(1, 5)) { 55 | console.log(number); //-> 1, 2, 3, 4 56 | } -------------------------------------------------------------------------------- /src/observer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 分发队列 3 | * subject = [observer, observer] 4 | * state change ==> 通知subject执行observer队列 5 | * api: subscribe(fn) 6 | * 例子: redux 7 | */ 8 | const observerPattern = () => { 9 | const subject = []; 10 | return { 11 | subscribe: (observer) => { 12 | subject.push(observer); 13 | }, 14 | notify: (value) => { 15 | subject.forEach((observer) => { 16 | observer(value); 17 | }); 18 | }, 19 | }; 20 | }; 21 | const observerP = observerPattern(); 22 | observerP.subscribe((value) => { 23 | // 打日志 24 | console.log(value); 25 | }); 26 | observerP.subscribe((value) => { 27 | // 改变preview 28 | document.getElementById('preview').innerHTML = value; 29 | }); 30 | document.getElementById('input').addEventListener('input', (event) => { 31 | let value = event.target.value; 32 | observerP.notify(value); 33 | }); 34 | -------------------------------------------------------------------------------- /src/publish-subscribe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 实现的功能 3 | * on('topic', fn), 4 | * trigger('topic') ==> fn要执行 5 | * off('topic', fn) ==> fn移除 6 | * message pattern 7 | * publishers 8 | * ==> 消息topic 9 | * receivers 10 | */ 11 | const app = { 12 | oncePool: {}, 13 | pool: {}, 14 | on: function(topic, fn) { 15 | if (this.pool[topic] ) { 16 | this.pool[topic].push(fn); 17 | } else { 18 | this.pool[topic] = [fn]; 19 | } 20 | }, 21 | trigger: function(topic) { 22 | if (this.pool[topic]) { 23 | this.pool[topic].forEach((fn) => { 24 | fn(); 25 | }); 26 | } 27 | if (this.oncePool[topic]) { 28 | this.oncePool[topic].forEach((fn) => { 29 | fn(); 30 | }); 31 | this.oncePool[topic] = []; 32 | } 33 | }, 34 | off: function(topic, fn) { 35 | // ? 36 | }, 37 | once: function(topic, fn) { 38 | if (this.oncePool[topic] ) { 39 | this.oncePool[topic].push(fn); 40 | } else { 41 | this.oncePool[topic] = [fn]; 42 | } 43 | } 44 | }; 45 | 46 | const fn = () => { 47 | console.log('0 --- hello world'); 48 | } 49 | const fn1 = () => { 50 | console.log('1 ---- hello world '); 51 | } 52 | const fn2 = () => { 53 | console.log('once ---- hello world '); 54 | } 55 | app.on('click', fn); 56 | app.on('click', fn1); 57 | app.once('click', fn2); 58 | app.trigger('click'); // 打印hello world 59 | app.trigger('click'); // 打印hello world 60 | app.trigger('click'); // 打印hello world 61 | -------------------------------------------------------------------------------- /src/singleton.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * restricts the instantiation of a class to one object 4 | * 5 | * An implementation of the singleton pattern must: 6 | * ensure that only one instance of the singleton class ever exists; and 7 | * provide global access to that instance. 8 | */ 9 | 10 | const singleton = () => { 11 | let instance = null; 12 | let singletonConstructor = function() { 13 | // 14 | }; 15 | return { 16 | getInstance: () => { 17 | if (instance === null) { 18 | instance = new singletonConstructor(); 19 | } 20 | return instance; 21 | } 22 | }; 23 | }; 24 | 25 | export const openModalSingleton = ((dom) => { 26 | let instance = null; 27 | let singletonConstructor = function() { 28 | // 29 | }; 30 | return { 31 | openModal: () => { 32 | dom.display = 'block'; 33 | if (instance === null) { 34 | instance = new singletonConstructor(); 35 | dom.innerHTML = instance; 36 | } 37 | return instance; 38 | }, 39 | closeModal: () => { 40 | dom.display = 'none'; 41 | } 42 | }; 43 | })(document.getElementById('root')); 44 | import { openModalSingleton } from './openModalSingleton'; 45 | 46 | openModalSingleton.openModal(); 47 | openModalSingleton.openModal(); 48 | openModalSingleton.openModal(); 49 | openModalSingleton.closeModal(); 50 | --------------------------------------------------------------------------------