最近再准备秋招,然后顺便把过去空白的设计模式相关概念补一补,这些内容都是从《JavaScript设计模式与开发实践》一书中整理出来的

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用场景:一个单一对象。比如:登录弹窗,无论点击多少次,登录弹窗只会被创建一次

简单版实现方法:判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。 拓展:

透明的单例模式:解决了简单单例的不透明性,使用者需知道其是一个单例对象才能进行获取

代理实现单例模式:创建单例和管理单例逻辑分开,管理单例逻辑放在代理类中

惰性单例技术:合适的时候才创建对象,并且只创建唯一的一个

JavaScript中的单例:全局变量当成单例来使用,缺点:命名空间污染

定义:将一个个算法(解决方案)封装在一个个策略类中,并且使他们可以相互替换

特点:一个基于策略模式的算法至少由两部分组成,一部分是策略类,封装了具体算法负责计算过程,另一部分是环境类,接受客户请求,将请求托付给某一个策略类

优点:

  • 策略模式可以避免代码中的多重判断条件。

  • 策略模式很好的体现了开放-封闭原则,将一个个算法(解决方案)封装在一个个策略类中。便于切换,理解,扩展。

  • 策略中的各种算法可以重复利用在系统的各个地方,避免复制粘贴。

  • 策略模式在程序中或多或少的增加了策略类。但比堆砌在业务逻辑中要清晰明了。

  • 违反最少知识原则,必须要了解各种策略类,才能更好的在业务中应用。

    应用场景:根据不同的员工绩效计算不同的奖金;表单验证中的多种校验规则。

定义:为一个对象提供一个代用品或占位符,以便控制对它的访问。

应用场景:图片懒加载(先通过一张loading图占位,然后通过异步的方式加载图片,等图片加载好了再把完成的图片加载到img标签里面。)

//TODO

定义:又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

场景:订阅感兴趣的专栏和公众号。

实现方法:

  • 先指定好发布者

  • 给发布者加一个缓存列表,用于存储回调函数通知订阅者

  • 发布消息时,遍历缓存列表,触发存放的订阅者回调函数

    简单版代码实现:

    1. 1 let event = {
    2. 2 clientList: [],
    3. 3 listen: function(key, fn) {
    4. 4 if (!this.clientList[key]) {
    5. 5 // 如果没有订阅过此类消息,则给该类消息创建一个缓存列表
    6. 6 this.clientList[key] = []
    7. 7 }
    8. 8 this.clientList[key].push(fn)
    9. 9 },
    10. 10 trigger: function() {
    11. 11 // 取第一个参数,即key值
    12. 12 const key = Array.prototype.shift.call(arguments)
    13. 13 const fns = this.clientList[key]
    14. 14 // 如果没有订阅该消息则返回
    15. 15 if (!fns || fns.length === 0) {
    16. 16 return false
    17. 17 }
    18. 18 // 遍历列表
    19. 19 for (var i = 0, fn; (fn = fns[i]); i++) {
    20. 20 fn.apply(this, arguments)
    21. 21 }
    22. 22 },
    23. 23 remove: function(key, fn) {
    24. 24 // 取消订阅
    25. 25 let fns = this.clientList[key]
    26. 26 if (!fns) {
    27. 27 return flase
    28. 28 }
    29. 29 if (!fn) {
    30. 30 // 如果key对应的消息没人订阅则直接返回
    31. 31 fns && (fns.length = 0)
    32. 32 } else {
    33. 33 for (let l = fns.length - 1; l >= 0; l--) {
    34. 34 let _fn = fns[l]
    35. 35 if (_fn === fn) {
    36. 36 fns.splice(l, 1)
    37. 37 }
    38. 38 }
    39. 39 }
    40. 40 },
    41. 41 }
    42. 42
    43. 43 let salesOffices = {}
    44. 44 installEvent(salesOffices)
    45. 45 salesOffices.listen('123', fn1 = function(squareMeter) {
    46. 46 console.log('面积为1:', squareMeter)
    47. 47 })
    48. 48 salesOffices.listen('123', fn2 = function(squareMeter) {
    49. 49 console.log('面积为2:', squareMeter)
    50. 50 })
    51. 51 salesOffices.trigger('123', fn1)
    52. 52 salesOffices.remove('123',fn1)
    53. 53 salesOffices.trigger('123', fn1)
    54. 54
    55. 55
    56. 56

     

定义:通过一个中介者对象,其他所有相关对象都通过该中介者对象来通信,而不是互相引用,当其中的一个对象发生改变时,只要通知中介者对象就可以。可以解除对象与对象之间的紧耦合关系。

应用场景: 例如购物车需求,存在商品选择表单、颜色选择表单、购买数量表单等等,都会触发change事件,那么可以通过中介者来转发处理这些事件,实现各个事件间的解耦,仅仅维护中介者对象即可。

定义:在不改变对象自身的基础上,在程序运行期间给对象动态的添加方法。

应用场景: 有方法维持不变,在原有方法上再挂载其他方法来满足现有需求;函数的解耦,将函数拆分成多个可复用的函数,再将拆分出来的函数挂载到某个函数上,实现相同的效果但增强了复用性。

参考书籍:JavaScript设计模式与开发实践 曾探

版权声明:本文为liuarui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liuarui/p/11390969.html