中介者模式(Mediator)
Mediator.js
1 (function(factory) { 2 var root = window || (typeof self == 'object' && self.self == self && self); 3 var Mediator = factory(root); 4 5 root.Mediator = new Mediator(); 6 })(function(root) { 7 8 function Mediator() { 9 if (!this instanceof Mediator) { 10 return new Mediator(); 11 } else { 12 this._topics = new Topic(''); 13 } 14 } 15 16 Mediator.version = '1.0'; 17 18 Mediator.prototype = { 19 getTopic: function(namespace) { 20 var topic = this._topics; 21 var namespaceArr = namespace.split(':'); 22 23 if (namespace == '') { 24 return topic; 25 } 26 27 if (namespaceArr.length > 0) { 28 for (var i = 0, j = namespaceArr.length; i < j; i++) { 29 if (!topic.hasTopic(namespaceArr[i])) { 30 topic.addTopic(namespaceArr[i]); 31 } 32 topic = topic.getTopic(namespaceArr[i]); 33 } 34 } 35 36 return topic; 37 }, 38 subscribe: function(topicName, fn, options, context) { 39 var options = options || {}, 40 context = context || {}, 41 topic = this.getTopic(topicName); 42 var sub = topic.addSubscriber(fn, options, context); 43 44 return sub; 45 }, 46 getSubscriber: function(topicName, id) { 47 return this.getTopic(topicName || '').getSubscriber(id); 48 }, 49 removeSubscriber: function(topicName, id) { 50 this.getTopic(topicName).removeSubscriber(id); 51 }, 52 publish: function(topicName) { 53 var args = Array.prototype.slice.call(arguments, 1), 54 topic = this.getTopic(topicName); 55 56 args.push(topic); 57 topic.publish(args); 58 } 59 }; 60 61 var getID = (function() { 62 var i = 0; 63 return function() { 64 return i++; 65 } 66 })(); 67 68 function extend(prev, next) { 69 if (typeof next != 'object' || typeof prev != 'object') { 70 return {}; 71 } 72 for (var i in next) { 73 if (next.hasOwnProperty(i)) { 74 prev[i] = next[i]; 75 } 76 } 77 return prev; 78 } 79 80 function Subscriber(fn, options, context) { 81 if (!this instanceof Subscriber) { 82 return new Subscriber(fn, options, context); 83 } else { 84 this.id = getID(); 85 this.fn = fn; 86 this.options = extend(this.options, options); 87 this.context = context; 88 this.topic = null; 89 } 90 } 91 92 function Topic(namespace) { 93 if (!this instanceof Topic) { 94 return new Topic(namespace); 95 } else { 96 this.namespace = namespace || ''; 97 this._callbacks = []; 98 this._topics = {}; 99 this.stoped = false; 100 } 101 } 102 103 Topic.prototype = { 104 addSubscriber: function(fn, options, context) { 105 var callback = new Subscriber(fn, options, context); 106 this._callbacks.push(callback); 107 callback.topic = this; 108 return callback.id; 109 }, 110 removeSubscriber: function(id) { 111 if (!id) { 112 this._callbacks = []; 113 114 for (var x in this._topics) { 115 if (this._topics.hasOwnProperty(x)) { 116 this._topics[x].removeSubscriber(id); 117 } 118 } 119 } 120 121 for (var y = 0, l = this._callbacks.length; y < l; y++) { 122 if (this._callbacks[y].id == id || this._callbacks[y].fn == id) { 123 this._callbacks[y].topic = null; 124 this._callbacks.splice(y, 1); 125 y--; 126 l--; 127 } 128 } 129 }, 130 stopPropagation: function(){ 131 this.stoped = true; 132 }, 133 getSubscriber: function(id) { 134 for (var x = 0, l = this._callbacks.length; x < l; x++) { 135 var callback = this._callbacks[x]; 136 if (callback.id == id || callback.fn == id) { 137 return callback; 138 } 139 } 140 141 for (var y in this._topics) { 142 if (this._topics.hasOwnProperty(y)) { 143 var sub = this._topics[y].getSubscriber(id); 144 if (sub != undefined) { 145 return sub; 146 } 147 } 148 } 149 }, 150 addTopic: function(topic) { 151 this._topics[topic] = new Topic((this.namespace?this.namespace+':' : '') + topic); 152 return this._topics[topic]; 153 }, 154 hasTopic: function(topic) { 155 return this._topics.hasOwnProperty(topic); 156 }, 157 getTopic: function(topic) { 158 return this._topics[topic]; 159 }, 160 publish: function(data) { 161 console.log('Published By: '+this.namespace); 162 163 for (var x = 0, l = this._callbacks.length; x < l; x++) { 164 var callback = this._callbacks[x]; 165 var len; 166 167 callback.fn.apply(callback.context, data); 168 169 if (this._callbacks.length < l) { 170 x--; 171 l = this._callbacks.length; 172 } 173 } 174 175 for (var y in this._topics) { 176 if (!this.stoped) { 177 if (this._topics.hasOwnProperty(y)) { 178 this._topics[y].publish(data); 179 } 180 } 181 } 182 183 this.stoped = false; 184 } 185 } 186 187 Mediator.prototype.Subscriber = Subscriber; 188 Mediator.prototype.Topic = Topic; 189 190 return Mediator; 191 });
index.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> 5 <script type="text/javascript" src="./Mediator.js"></script> 6 </head> 7 <body> 8 9 <script type="text/javascript"> 10 11 Mediator.subscribe('new', function(data) { 12 console.log(data); 13 console.log('subscrib something. ---msg'); 14 }, {}, this); 15 16 setTimeout(function() { 17 Mediator.publish('new', 'text'); 18 }, 500); 19 20 21 console.log('------------divider-----------'); 22 23 Mediator.subscribe('user:new', function(name, age) { 24 console.log('name:'+name+', age:'+age); 25 }, {}, this); 26 27 Mediator.subscribe('user:new', function(name, age) { 28 console.log('Log : Save a new User.'); 29 }, {}, this); 30 31 Mediator.publish('user:new', 'Dong', '25'); 32 33 console.log('------------divider-----------'); 34 35 console.log(Mediator.getTopic('user:new')); 36 37 </script> 38 39 </body> 40 </html>