[关闭]
@EncyKe 2017-03-10T03:43:44.000000Z 字数 17097 阅读 1122

读书:《JavaScript 设计模式》

#读书



0. JS 中几种用于实现模块的方法

1. Constructor 模式

1.1. 基本 constructor

  1. /**
  2. * @module
  3. * @description 构造模式示例:汽车构造器
  4. * @example
  5. * var mondeo = new Car('Ford Mondeo', 2010, 5000);
  6. * mondeo.toString();
  7. */
  8. function Car(model, year, miles) {
  9. // 公有属性:由 this 暴露
  10. this.model = model;
  11. this.year = year;
  12. this.miles = miles;
  13. // 私有属性
  14. var action = ' has done ';
  15. var unit = ' miles.';
  16. // 公有方法
  17. this.toString = function (){
  18. return this.model + action + this.miles + unit;
  19. };
  20. }

1.2. 与 prototype 混合的 constructor

  1. /**
  2. * @module
  3. * @description 构造模式示例:汽车构造器
  4. * @example
  5. * var mondeo = new Car('Ford Mondeo', 2010, 5000);
  6. * mondeo.toString();
  7. */
  8. function Car(model, year, miles) {
  9. // 公有属性:由 this 暴露
  10. this.model = model;
  11. this.year = year;
  12. this.miles = miles;
  13. // 私有属性
  14. var action = ' has done ';
  15. var unit = ' miles.';
  16. // 公有方法
  17. Car.prototype.toString = function (){
  18. return this.model + action + this.miles + unit;
  19. };
  20. }

或者——

  1. /**
  2. * @module
  3. * @description 构造模式示例:汽车构造器
  4. * @example
  5. * var mondeo = new Car('Ford Mondeo', 2010, 5000);
  6. * mondeo.toString();
  7. */
  8. function Car(model, year, miles) {
  9. // 公有属性:由 this 暴露
  10. this.model = model;
  11. this.year = year;
  12. this.miles = miles;
  13. // 私有属性
  14. var action = ' has done ';
  15. var unit = ' miles.';
  16. // 公有方法
  17. Car.prototype = {
  18. wheels: 4,
  19. toString: function () {
  20. return this.model + action + this.miles + unit;
  21. }
  22. };
  23. }

2. Prototype 模式

  1. /**
  2. * @module
  3. * @description 原型模式示例:汽车构造器
  4. * @example
  5. * var mondeo = new Car();
  6. * mondeo.name = 'Ford Mondeo';
  7. * mondeo.year = 2010;
  8. * mondeo.miles = 5000;
  9. * mondeo.toString();
  10. */
  11. function Car() {};
  12. Car.prototype = {
  13. constructor: Car,
  14. model: '',
  15. year: 0,
  16. miles: 0,
  17. toString: function () {
  18. return this.model + ' has done ' + this.miles + ' miles.';
  19. }
  20. };
  1. /**
  2. * @module
  3. * @description 模式示例:汽车构造器
  4. * @example
  5. * var yourCar = Object.create(myCar);
  6. * console.log(yourCar.name);
  7. */
  8. var myCar = {
  9. name: 'Ford Mondeo',
  10. drive: function () {
  11. console.log('I am driving.');
  12. },
  13. panic: function () {
  14. console.log('Wait, how do you stop this thing?');
  15. }
  16. };

3. Module 模式

3.1. 对象字面量定义模块

  1. /**
  2. * @module
  3. * @description 模块模式示例:汽车构造器
  4. * @example
  5. * car.toString();
  6. * car.reconfig({
  7. * model: 'civic',
  8. * year: 2009,
  9. * miles: 20000
  10. * });
  11. */
  12. var car = {
  13. wheels: 4,
  14. // 配置
  15. config: {
  16. model: 'Ford Mondeo',
  17. year: 2010,
  18. miles: 5000
  19. },
  20. // 基本方法
  21. toString: function () {
  22. return this.model + ' has done ' + this.miles + ' miles.';
  23. },
  24. // 重写当前配置
  25. reconfig: function (newConfig) {
  26. if (typeof newConfig === 'object') {
  27. this.config = newConfig;
  28. return this.config.model;
  29. }
  30. }
  31. };

3.2. 模块模式

  1. /**
  2. * @module
  3. * @description 模块模式示例:购物车
  4. * @example
  5. * cartModule.addItem({item: 'food', price: 5});
  6. * cartModule.addItem({item: 'wine', price: 20});
  7. * cartModule.getItemCount(); // ==> 2
  8. * cartModule.getTotal(); // ==> 25
  9. */
  10. var cartModule = (function () {
  11. /**
  12. * @description 私有的购物车对象
  13. * @type {Array}
  14. */
  15. var cart = [];
  16. /**
  17. * @description 私有的方法
  18. */
  19. function privateMethods () {
  20. console.log('这个私有方法工作了。');
  21. }
  22. /**
  23. * @return {Object} - 暴露公有对象,被自动赋值给 cartModule
  24. */
  25. return {
  26. /**
  27. * @description 添加物品到购物车
  28. * @param {Object} val - 需要添加的物品
  29. * @property {String} item - 物品名称
  30. * @property {Number} price - 物品单价
  31. */
  32. addItem: function (val) {
  33. cart.push(val);
  34. },
  35. /**
  36. * @description 获取购物车里的物品数
  37. * @return {Number} - 购物车里的物品数
  38. */
  39. getItemCount: function () {
  40. return cart.length;
  41. },
  42. /**
  43. * @description 获取购物车里的物品总值
  44. * @return {[type]} [description]
  45. */
  46. getTotal: function () {
  47. var itemCount = this.getItemCount();
  48. var total = 0;
  49. while (itemCount--) {
  50. total += cart[itemCount].price;
  51. };
  52. return total;
  53. },
  54. /**
  55. * @description 私有方法的公有形式别名
  56. * @type {Function}
  57. */
  58. aliasPrivateMethods: privateMethods,
  59. };
  60. })();

4. Revealing Module 模式

  1. /**
  2. * @module
  3. * @description 揭示模块示例:简单问候
  4. * @example
  5. * greetingModule.setName('Me');
  6. * greetingModule.getName(); // ==> Name: Me
  7. * greetingModule.greeting; // ==> "Hello, world!"
  8. */
  9. var greetingModule = function () {
  10. var privateVar = 'FooBar';
  11. var publicVar = 'Hello, world!';
  12. function privateMethod() {
  13. console.log('Name: ' + privateVar);
  14. }
  15. function publicSetName(name) {
  16. privateVar = name;
  17. }
  18. function publicGetName() {
  19. privateMethod();
  20. }
  21. // 将暴露的公有指针指向私有方法及属性上;
  22. return {
  23. setName: publicSetName,
  24. getName: publicGetName,
  25. greeting: publicVar,
  26. };
  27. }();

5. Singleton 模式

  1. /**
  2. * @module
  3. * @description 单例模式示例:创建随机数字
  4. * @example
  5. * var randomNumberA = randomNumberModule.getInstance();
  6. * var randomNumberB = randomNumberModule.getInstance();
  7. * randomNumberA.getRandomNum() === randomNumberB.getRandomNum(); // ==> true
  8. */
  9. var randomNumberModule = (function () {
  10. var instance;
  11. function init() {
  12. // 私有变量;
  13. var privateVar = '私有变量';
  14. var privateRandomNum = Math.random();
  15. // 私有方法;
  16. function privateMethod() {
  17. console.log('私有方法工作了。');
  18. }
  19. // 返回公有变量及公有方法;
  20. return {
  21. publicProp: '公有变量',
  22. publicMethod: function () {
  23. console.log('公有方法工作了。');
  24. },
  25. getRandomNum: function () {
  26. return privateRandomNum;
  27. },
  28. };
  29. }
  30. return {
  31. /**
  32. * @description 获取单例模块的实例
  33. * 1. 如若存在则返回;
  34. * 2. 如若不存在则创建;
  35. */
  36. getInstance: function () {
  37. if (!instance) {
  38. instance = init();
  39. }
  40. return instance;
  41. }
  42. };
  43. })();

6. Observer 模式

Subject
目标,维护一系列的观察者,方便添加 / 删除观察者;
Observer
观察者,为那些在目标状态发生变更时需要获得通知的对象提供一个更新接口;
ConcreteSubject
具体目标,状态发生变更时,向 Observer 发送通知,存储 ConcreteSubject 的状态;
ConcreteObserver
具体观察者,存储一个指向 ConcreteSubject 的引用,实现 Observer 的更新接口,以使自身状态与目标的状态保持一致;
  1. /**
  2. * @module
  3. * @description 观察者模式示例:自定义事件
  4. */
  5. function EventTarget(){
  6. this.handlers = {};
  7. }
  8. EventTarget.prototype = {
  9. constructor: EventTarget,
  10. addHandler: function(type, handler){
  11. // 如果 EventTarget 的实例上还没有该事件类型,便建立该事件类型
  12. if (typeof this.handlers[type] === 'undefined'){
  13. this.handlers[type] = [];
  14. }
  15. // 如果已有该事件类型,便将事件处理程序推入该事件的处理程序列表中
  16. this.handlers[type].push(handler);
  17. },
  18. fire: function(event){
  19. if (!event.target){
  20. event.target = this;
  21. }
  22. // 检查事件类型是否已注册
  23. if (this.handlers[event.type] instanceof Array){
  24. // handlers 为所有事件处理程序的数组
  25. var handlers = this.handlers[event.type];
  26. // 触发数组中的每一个事件处理程序
  27. for (var i = 0, len = handlers.length; i < len; i++){
  28. handlers[i](event);
  29. }
  30. }
  31. },
  32. removeHandler: function(type, handler){
  33. // 检查事件类型是否已注册
  34. if (this.handlers[type] instanceof Array){
  35. var handlers = this.handlers[type];
  36. // 遍历寻找事件处理程序
  37. for (var i = 0, len = handlers.length; i < len; i++){
  38. if (handlers[i] === handler){
  39. break;
  40. }
  41. }
  42. // 删除传入的事件处理程序的对应项
  43. handlers.splice(i, 1);
  44. }
  45. }
  46. };
  47. /**
  48. * @example
  49. * @description 处理方法
  50. * @param {Object} event - 待处理的事件对象
  51. */
  52. function handleMessage(event) {
  53. console.log('Message received: ' + event.message);
  54. }
  55. // 创建一个新对象
  56. var target = new EventTarget();
  57. // 添加一个事件处理程序
  58. target.addHandler('message', handleMessage);
  59. // 触发事件,以事件对象的形式传入事件的相关信息
  60. target.fire({
  61. type: 'message',
  62. message: 'Hello world!'
  63. });
  64. // ==> Message received: Hello world!
  65. // 删除事件处理程序
  66. target.removeHandler('message', handleMessage);
  67. // 删除后无法再触发
  68. target.fire({
  69. type: 'message',
  70. message: 'Foo Bar!'
  71. });

示例——

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Observer Demo</title>
  5. </head>
  6. <body>
  7. <button id="addNewObserver">Add New Observer checkbox</button>
  8. <input id="mainCheckbox" type="checkbox" />
  9. <div id="observerContainer"></div>
  10. <script type="text/javascript">
  11. /**
  12. * @description 模拟一个目标可能拥有的一系列依赖 Observer
  13. */
  14. function ObserverList() {
  15. this.observerList = [];
  16. }
  17. ObserverList.prototype.Add = function(obj) {
  18. return this.observerList.push(obj);
  19. };
  20. ObserverList.prototype.Empty = function() {
  21. this.observerList = [];
  22. };
  23. ObserverList.prototype.Count = function() {
  24. return this.observerList.length;
  25. };
  26. ObserverList.prototype.Get = function(index) {
  27. if (index > -1 && index < this.observerList.length) {
  28. return this.observerList[index];
  29. }
  30. };
  31. ObserverList.prototype.Insert = function(obj, index) {
  32. var pointer = 1;
  33. if (index === 0) {
  34. this.observerList.unshift(obj);
  35. pointer = index;
  36. } else if (index === this.observerList.length) {
  37. this.observerList.push(obj);
  38. pointer = index;
  39. };
  40. return pointer;
  41. };
  42. ObserverList.prototype.IndexOf = function(obj, startIndex) {
  43. var i = startIndex;
  44. var pointer = -1;
  45. var len = this.observerList.length;
  46. while (i < len) {
  47. if (this.observerList[i] === obj) {
  48. pointer = i;
  49. };
  50. i++;
  51. };
  52. return pointer;
  53. };
  54. ObserverList.prototype.RemoveIndexAt = function(index) {
  55. if (index === 0) {
  56. this.observerList.shift();
  57. } else if (index === this.observerList.length - 1) {
  58. this.observerList.pop();
  59. };
  60. };
  61. function extend(obj, extension) {
  62. for (var key in obj) {
  63. extension[key] = obj[key];
  64. }
  65. }
  66. /**
  67. * @description 模拟目标及其在观察者列表上添加、删除或通知观察者的能力
  68. */
  69. function Subject() {
  70. this.observers = new ObserverList();
  71. }
  72. Subject.prototype.AddObserver = function(observer) {
  73. this.observers.Add(observer);
  74. };
  75. Subject.prototype.RemoveObserver = function(observer) {
  76. this.observers.RemoveIndexAt(this.observers.IndexOf(observer, 0));
  77. };
  78. Subject.prototype.Notify = function(context) {
  79. var observerCount = this.observers.Count();
  80. for (var i = 0; i < observerCount; i++) {
  81. this.observers.Get(i).Update(context);
  82. }
  83. };
  84. /**
  85. * @description 创建新的 Observer
  86. */
  87. function Observer() {
  88. this.Update = function (value) {
  89. this.checked = value;
  90. };
  91. };
  92. </script>
  93. <script type="text/javascript">
  94. var button = document.getElementById('addNewObserver');
  95. var input = document.getElementById('mainCheckbox');
  96. var div = document.getElementById('observerContainer');
  97. /**
  98. * 具体目标
  99. */
  100. // 用 Subject 扩展 input;
  101. extend(new Subject(), input);
  102. // 单击 input 触发通知到观察者上
  103. input.onclick = new Function('input.Notify(input.checked)');
  104. button.onclick = AddNewObserver;
  105. /**
  106. * 具体观察者
  107. */
  108. function AddNewObserver() {
  109. // 创建需要添加的新 checkbox
  110. var check = document.createElement('input');
  111. check.type = 'checkbox';
  112. // 利用 Observer 类扩展 checkbox
  113. extend(new Observer(), check);
  114. // 重写自定义行为
  115. // check.Update = function (value) {
  116. // this.checked = value;
  117. // };
  118. // 为主 subject 的观察者列表添加新的观察者
  119. input.AddObserver(check);
  120. // 将观察者附加到容器上
  121. div.appendChild(check);
  122. }
  123. </script>
  124. </body>
  125. </html>

7. Publish/Subscribe 模式

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>PubSub Demo</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript">
  9. /**
  10. * @module
  11. * @description 发布订阅模式模块示例:收发邮件系统
  12. */
  13. var pubsub = {};
  14. (function (q) {
  15. // 主题及订阅者对象
  16. var topics = {};
  17. var subUid = -1;
  18. /**
  19. * @description 发布事件
  20. * @param {String} topic - 指定主题
  21. * @param {*} args - 附带参数
  22. * @return {Object} - 返回 pubsub 对象
  23. */
  24. q.publish = function (topic, args) {
  25. // 指定主题不存在则返回
  26. if (!topics[topic]) {
  27. return false;
  28. }
  29. // 获取指定主题下的订阅者及其个数
  30. var subscribers = topics[topic];
  31. var len = subscribers ? subscribers.length : 0;
  32. // 逐个执行该主题上订阅者的回调方法
  33. while (len--) {
  34. subscribers[len].func(topic, args);
  35. }
  36. return this;
  37. };
  38. /**
  39. * @description 订阅事件,topic/event 触发时执行事件
  40. * @param {String} topic - 指定主题
  41. * @param {Function} func - 回调方法
  42. * @return {String} token - 标记
  43. */
  44. q.subscribe = function (topic, func) {
  45. // 指定主题不存在则创建
  46. if (!topics[topic]) {
  47. topics[topic] = [];
  48. }
  49. var token = (++subUid).toString();
  50. // 指定主题中新增订阅者
  51. topics[topic].push({
  52. token: token,
  53. func: func
  54. });
  55. return token;
  56. };
  57. /**
  58. * @description 取消订阅
  59. * @param {String} token - 订阅者的标记
  60. * @return {String} token - 更新的标记
  61. */
  62. q.unsubscribe = function (token) {
  63. for (var m in topics ) {
  64. if (topics[m]) {
  65. for (var i = 0, len = topics[m].length; i < len; i++) {
  66. // 依据 token 删除订阅者
  67. if (topics[m][i].token === token) {
  68. topics[m].splice(i, 1);
  69. return token;
  70. }
  71. }
  72. }
  73. }
  74. return this;
  75. }
  76. }(pubsub));
  77. </script>
  78. <script type="text/javascript">
  79. /**
  80. * @description 消息记录器
  81. * @param {Object} topics - 通过订阅者接收到主题
  82. * @param {*} data - 数据
  83. */
  84. var messageLoader = function (topics, data) {
  85. console.log('Logging: ' + topics + ': ' + data);
  86. };
  87. // 订阅者监听订阅的主题,一旦该主题广播一个通知,订阅者就调用回调函数
  88. var subscription = pubsub.subscribe('inbox/newMessage', messageLoader);
  89. // 发布者发布程序感兴趣的主题或通知
  90. pubsub.publish('inbox/newMessage', 'Hello world');
  91. // ==> Logging: inbox/newMessage: Hello world
  92. // 取消订阅
  93. pubsub.unsubscribe(subscription);
  94. pubsub.publish('inbox/newMessage','Foo Bar.');
  95. </script>
  96. </body>
  97. </html>

8. Mediator 模式

  1. var mediator = (function () {
  2. var topics = {};
  3. var subscribe = function () {
  4. if (!topics[topic]) {
  5. topics[topic] = [];
  6. }
  7. topics[topic].push({
  8. context: this,
  9. callback: fn
  10. });
  11. return this;
  12. };
  13. var publish = function () {
  14. var args;
  15. if (!topics[topic]) {
  16. return false;
  17. }
  18. args = Array.prototype.slice.call(arguments, 1);
  19. for (var i = 0, l = topics[topic].length; i < l; i++) {
  20. var subscription = topics[topic][i];
  21. subscription.callback.apply(subscription.context, args);
  22. }
  23. return this;
  24. };
  25. return {
  26. Publish: publish,
  27. Subscribe: subscribe,
  28. installTo: function (obj) {
  29. obj.subscribe = subscribe;
  30. obj.publish = publish;
  31. }
  32. };
  33. })

9. Command 模式

  1. (function () {
  2. var CarManager = {
  3. // 请求信息
  4. requestInfo: function (model, id) {
  5. return 'The information for ' + model + ' with ID ' + id + ' is foobar';
  6. },
  7. // 订购汽车
  8. buyVehicle: function (model, id) {
  9. return 'You have successfully purchased Item ' + id + ', a ' + model;
  10. },
  11. // 组织一个view
  12. arrangeViewing: function (model, id) {
  13. return 'You have successfully booked a viewing of ' + model+'('+id +')';
  14. }
  15. };
  16. })();

10. Facade 模式

  1. var addMyEvent = function (el, ev, fn) {
  2. if (el.addEventListener) {
  3. el.addEventListener(ev, fn, false);
  4. } else if (el.attachEvent) {
  5. el.attachEvent('on' + ev, fn);
  6. } else {
  7. el['on' + ev] = fn;
  8. }
  9. };

11. Factory 模式

  1. /**
  2. * @module
  3. * @description 工厂模式示例:汽车构造器
  4. * @example
  5. * var mondeo = new Car('Ford Mondeo', 2010, 5000);
  6. * mondeo.toString();
  7. */
  8. var Car = (function () {
  9. var action = ' has done ';
  10. var unit = ' miles.';
  11. var Car = function (model, year, miles) {
  12. this.model = model;
  13. this.year = year;
  14. this.miles = miles;
  15. this.toString = function (){
  16. return this.model + action + this.miles + unit;
  17. };
  18. };
  19. return function (model, year, miles) {
  20. return new Car(model, year, miles);
  21. };
  22. })();
  1. var page = page || {};
  2. page.dom = page.dom || {};
  3. // 子函数 1:处理文本
  4. page.dom.Text = function () {
  5. this.insert = function (where) {
  6. var txt = document.createTextNode(this.url);
  7. where.appendChild(txt);
  8. };
  9. };
  10. // 子函数 2:处理链接
  11. page.dom.Link = function () {
  12. this.insert = function (where) {
  13. var link = document.createElement('a');
  14. link.href = this.url;
  15. link.appendChild(document.createTextNode(this.url));
  16. where.appendChild(link);
  17. };
  18. };
  19. // 子函数 3:处理图片
  20. page.dom.Image = function () {
  21. this.insert = function (where) {
  22. var im = document.createElement('img');
  23. im.src = this.url;
  24. where.appendChild(im);
  25. };
  26. };
  27. // 定义工厂处理函数
  28. /**
  29. * @module
  30. * @description 工厂处理函数
  31. * @example
  32. * var o = page.dom.factory('Link');
  33. * o.url = 'http://www.cnblogs.com';
  34. * o.insert(document.body);
  35. */
  36. page.dom.factory = function (type) {
  37. return new page.dom[type];
  38. }

12. Mixin 模式

  1. // 定义简单的 Car 构造函数
  2. var Car = function (settings) {
  3. this.model = settings.model || 'no model provided';
  4. this.color = settings.color || 'no colour provided';
  5. };
  6. // Mixin
  7. var Mixin = function () {};
  8. Mixin.prototype = {
  9. driveForward: function () {
  10. console.log('drive forward');
  11. },
  12. driveBackward: function () {
  13. console.log('drive backward');
  14. },
  15. driveSideways: function () {
  16. console.log('drive sideways');
  17. }
  18. };
  19. // 通过一个方法将现有对象扩展到另外一个对象上
  20. function augment(receivingClass, givingClass) {
  21. // 只提供特定的方法
  22. if (arguments[2]) {
  23. for (var i = 2, len = arguments.length; i < len; i++) {
  24. receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
  25. }
  26. }
  27. // 提供所有方法
  28. else {
  29. for (var methodName in givingClass.prototype) {
  30. // 确保接收类不包含所处理方法的同名方法
  31. if (!Object.hasOwnProperty(receivingClass.prototype, methodName)) {
  32. receivingClass.prototype[methodName] = givingClass.prototype[methodName];
  33. }
  34. // 另一方式:
  35. // if ( !receivingClass.prototype[methodName] ) {
  36. // receivingClass.prototype[methodName] = givingClass.prototype[methodName];
  37. // }
  38. }
  39. }
  40. }
  41. // 给 Car 构造函数增加 driveForward 和 driveBackward 两个方法
  42. augment(Car, Mixin, 'driveForward', 'driveBackward');
  43. // 创建一个新 Car
  44. var myCar = new Car({
  45. model: 'Ford Escort',
  46. color: 'blue'
  47. });
  48. // 测试确保新增方法可用
  49. myCar.driveForward(); // ==> drive forward
  50. myCar.driveBackward(); // ==> drive backward
  51. // 也可以通过不声明特定方法名的形式,将 Mixin 的所有方法都添加到 Car 里
  52. augment(Car, Mixin);
  53. var mySportsCar = new Car({
  54. model: 'Porsche',
  55. color: 'red'
  56. });
  57. mySportsCar.driveSideways(); // ==> drive sideways

13. Decorator 模式

  1. var tree = {};
  2. tree.decorate = function () {
  3. console.log('Make sure the tree won\'t fall');
  4. };
  5. tree.getDecorator = function (deco) {
  6. tree[deco].prototype = this;
  7. return new tree[deco];
  8. };
  9. tree.RedBalls = function () {
  10. this.decorate = function () {
  11. // 第 7 步:先执行原型(这时候是 Angel 了)的 decorate 方法
  12. this.RedBalls.prototype.decorate();
  13. // 第 8 步:再输出 red
  14. console.log('Put on some red balls');
  15. }
  16. };
  17. tree.BlueBalls = function () {
  18. this.decorate = function () {
  19. // 第 1 步:先执行原型的 decorate 方法
  20. this.BlueBalls.prototype.decorate();
  21. // 第 2 步:再输出 blue
  22. console.log('Add blue balls');
  23. }
  24. };
  25. tree.Angel = function () {
  26. this.decorate = function () {
  27. // 第 4 步:先执行原型(这时候是 BlueBalls 了)的 decorate 方法
  28. this.Angel.prototype.decorate();
  29. // 第 5 步:再输出 angel
  30. console.log('An angel on the top');
  31. }
  32. };
  33. // 第 3 步:将 BlueBalls 对象赋给 tree,这时候父原型里的 getDecorator 依然可用
  34. tree = tree.getDecorator('BlueBalls');
  35. // 第 6 步:将 Angel 对象赋给 tree,这时候父原型的父原型里的 getDecorator 依然可用
  36. tree = tree.getDecorator('Angel');
  37. // 第 9 步:将 RedBalls 对象赋给 tree
  38. tree = tree.getDecorator('RedBalls');
  39. // 第 10 步:执行 RedBalls 对象的 decorate 方法
  40. tree.decorate();

14. Flyweight 模式

  1. var Book = function(title, author, genre, pageCount, publisherID, ISBN){
  2. this.title = title;
  3. this.author = author;
  4. this.genre = genre;
  5. this.pageCount = pageCount;
  6. this.publisherID = publisherID;
  7. this.ISBN = ISBN;
  8. };
  9. /**
  10. * @description 书籍模块:工厂单例模式
  11. */
  12. var BookFactory = (function(){
  13. var existingBooks = {};
  14. return {
  15. createBook: function(title, author, genre, pageCount, publisherID, ISBN) {
  16. // 查找之前是否创建
  17. var existingBook = existingBooks[ISBN];
  18. if (existingBook) {
  19. return existingBook;
  20. } else {
  21. // 如果没有,就创建一个,然后保存
  22. var book = new Book(title, author, genre, pageCount, publisherID, ISBN);
  23. existingBooks[ISBN] = book;
  24. return book;
  25. }
  26. }
  27. }
  28. });
  29. /**
  30. * @description 借书管理模块:单例模式
  31. */
  32. var BookRecordManager = (function(){
  33. var bookRecordDatabase = {};
  34. return {
  35. // 添加借书记录
  36. addBookRecord: function(id, title, author, genre, pageCount, publisherID, ISBN, checkoutDate, checkoutMember, dueReturnDate, availability) {
  37. var book = bookFactory.createBook(title, author, genre, pageCount, publisherID, ISBN);
  38. bookRecordDatabase[id] = {
  39. checkoutMember: checkoutMember,
  40. checkoutDate: checkoutDate,
  41. dueReturnDate: dueReturnDate,
  42. availability: availability,
  43. book: book
  44. };
  45. },
  46. updateCheckoutStatus: function(bookID, newStatus, checkoutDate, checkoutMember, newReturnDate) {
  47. var record = bookRecordDatabase[bookID];
  48. record.availability = newStatus;
  49. record.checkoutDate = checkoutDate;
  50. record.checkoutMember = checkoutMember;
  51. record.dueReturnDate = newReturnDate;
  52. },
  53. extendCheckoutPeriod: function(bookID, newReturnDate){
  54. bookRecordDatabase[bookID].dueReturnDate = newReturnDate;
  55. },
  56. isPastDue: function(bookID) {
  57. var currentDate = new Date();
  58. return currentDate.getTime() > Date.parse(bookRecordDatabase[bookID].dueReturnDate);
  59. }
  60. };
  61. });

附:参考

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注