• 【学习笔记73】设计模式


    一、认识单利模式(设计模式)

    • 设计模式:为了 实现某一类功能的一个简洁优化的写法

    (一)单利模式

    • 一个构造函数(类), 一生只能有一个实例化对象

    (二)案例需求

    • 一个构造函数, 在实例化对象时, 判断是否为第一次实例化
    • 第一次创建一个实例化对象, 然后返回
    • 不是第一次想办法拿到第一次的实例化对象, 然后返回

    (三)解决方法

    • 拿一个变量, 初始值给一个null
    • 在实例化对象时, 第一次实例化, 直接将实例化赋值给变量, 然后将变量返回
    • 后续再实例化的时候, 直接返回刚才的变量

    (四)核心代码 

    1. class Dialog {
    2. constructor(title) {
    3. console.log('创建一个弹出框插入到页面中, 类型为: ')
    4. this.title = title
    5. }
    6. }
    7. let instance = null
    8. function newDialog(type) {
    9. if (instance === null) {
    10. instance = new Dialog(type)
    11. }
    12. return instance
    13. }
    14. const n1 = newDialog('警告')
    15. console.log(n1)
    16. const n2 = newDialog('文本')
    17. console.log(n2)

     二、单例模式变形

    1、代码的问题

    1. 全局多了一个变量instance

    2. 传递多个参数 ,无法生效

    3. 构造函数的类, 和实际使用创建的函数, 不是一个名字

    2、通过闭包, 解决问题1

    1. class Dialog {
    2. constructor(title) {
    3. console.log('创建一个弹出框插入到页面中, 类型为: ')
    4. this.title = title
    5. }
    6. }
    7. function fn(type) {
    8. let instance = null
    9. return function newDialog() {
    10. if (instance === null) {
    11. instance = new Dialog(type)
    12. }
    13. return instance
    14. }
    15. }
    16. const n1 = fn('警告')
    17. const res = n1()
    18. console.log(res)

    1. class Dialog {
    2. constructor(title) {
    3. console.log('创建一个弹出框插入到页面中, 类型为: ')
    4. this.title = title
    5. }
    6. }
    7. // 利用自执行函数 进一步优化
    8. const newDialog = (function fn() {
    9. let instance = null
    10. return function inner(type) {
    11. if (instance === null) {
    12. instance = new Dialog(type)
    13. }
    14. return instance
    15. }
    16. })()
    17. const n1 = newDialog('警告')
    18. console.log(n1)
    19. const n2 = newDialog('文本')
    20. console.log(n2)

     3、解决问题2:传递多个参数 ,无法生效

    1. class Dialog {
    2. constructor() {
    3. console.log('创建一个弹出框插入到页面中, 类型为: ')
    4. this.title = ''
    5. }
    6. // 每次需要给title赋值, 直接调用这个方法即可
    7. init(title) {
    8. this.title = title
    9. console.log('当前title的值为: ', title)
    10. }
    11. }
    12. const newDialog = (function fn() {
    13. let instance = null
    14. return function inner(type) {
    15. if (instance === null) {
    16. instance = new Dialog()
    17. }
    18. instance.init(type)
    19. return instance
    20. }
    21. })()
    22. const n1 = newDialog('警告')
    23. console.log(n1)
    24. const n2 = newDialog('文本')
    25. console.log(n2)

     4、解决 问题3:构造函数的类, 和实际使用创建的函数, 不是一个 名字

    1. const Dialog = (function fn() {
    2. let instance = null
    3. class Dialog {
    4. constructor() {
    5. console.log('创建一个弹出框插入到页面中, 类型为: ')
    6. this.title = ''
    7. }
    8. // 每次需要给title赋值, 直接调用这个方法即可
    9. init(title) {
    10. this.title = title
    11. console.log('当前title的值为: ', title)
    12. }
    13. }
    14. return function inner(type) {
    15. // 1. 自动帮我们创建一个对象, 自动帮我们把函数内部的this指向这个新建对象
    16. // 2. 手动往对象上添加属性
    17. // 3. 自动返回一个对象
    18. // 4. 构造函数内部不要写return, 返回一个基本数据类型, 写了和没写一样,
    19. // 如果返回一个引用数据类型, 写了构造函数就没用了
    20. if (instance === null) {
    21. instance = new Dialog()
    22. }
    23. instance.init(type)
    24. return instance
    25. }
    26. })()
    27. // // 单例模式, 一般不建议写 new
    28. const n1 = Dialog('警告')
    29. const n2 = Dialog('文本')
    30. const n3 = Dialog('红色警告')
    31. console.log(n1)
    32. console.log(n2)
    33. console.log(n3)
    34. console.log(n1 === n2)
    35. console.log(n2 === n3)
    36. console.log(n1 === n3)

    三、策略模式

    • 核心: 减少过多的 if...else...
    • 需求: 去购物, 购物总价1987     折扣: 8折   7折    300-30    500-50
    • 策略模式处理:  有一个数据结构,内部存储着各种折扣对应的计算总价方式
    1. // 70% '300-30' '500-50' 60% 75%
    2. let type = '80%';
    3. let total = 1987;
    4. if (type === '80%') {
    5. } else if (type === '70%') {
    6. } else if (type === '300-30') {
    7. } else if (type === '500-50') {
    8. } else if (type === '60%') {
    9. } else if (type === '75%') {
    10. }

    (一)基础版

    1. const price = (function(){
    2. let PriceList = {
    3. // '80%': (total) =>{}
    4. '80%': total =>total * 0.8,
    5. '70%': total =>total * 0.7,
    6. }
    7. return function inner(type, total){
    8. // console.log('inner函数开始执行,计算商品总价');
    9. // console.log(type);
    10. // console.log(PriceList[type]);
    11. // console.log(PriceList[type](total));
    12. return PriceList[type](total)
    13. }
    14. })()
    15. let newPrice1 = price('80%', 1000);
    16. let newPrice2 = price('70%', 1000);
    17. console.log(newPrice1);
    18. console.log(newPrice2);

    (二)进阶版

    1. const price = (function(){
    2. let PriceList = {
    3. // '80%': (total) =>{}
    4. '80%': total =>total * 0.8,
    5. '70%': total =>total * 0.7,
    6. }
    7. return function inner(type, total){
    8. // 新增其他折扣时
    9. inner.add = (key, value) =>{
    10. PriceList[key] = value;
    11. }
    12. // 只传递一个参数时
    13. inner.sub = (key) =>{
    14. PriceList[key] = null
    15. }
    16. // 打印PriceList列表时
    17. inner.GetList = () =>{
    18. return PriceList
    19. }
    20. return PriceList[type](total)
    21. }
    22. })()
    23. let newPrice1 = price('80%', 1000);
    24. let newPrice2 = price('70%', 1000);
    25. price.add('60%', total =>total * 0.6);
    26. let list = price.GetList();
    27. console.log(newPrice1);
    28. console.log(newPrice2);
    29. console.dir(price);

     四、发布订阅模式

    • 这个模式适用于大型项目的封装
    •  自行搜索:  Vue2 响应式原理
    • 除了 发布订阅模式, 还有一种叫观察者模式,这两个开发模式, 特别相似
    1. class observer {
    2. constructor(name) {
    3. // 模拟一个店员(不重要)
    4. this.name = name
    5. // 店员的记录手册
    6. this.message = {}
    7. }
    8. // 原型
    9. add(type, fn) {
    10. if (this.message[type] === undefined) {
    11. this.message[type] = []
    12. }
    13. this.message[type].push(fn)
    14. }
    15. tri(type) {
    16. // 调用这个方法, 通知对应的 人员 来购买
    17. // console.log(type)
    18. // console.log(this.message[type])
    19. this.message[type].forEach(item => {
    20. // console.log(item)
    21. item()
    22. })
    23. }
    24. remove(type, fn) {
    25. // console.log(type, fn)
    26. // console.log(this.message[type], fn)
    27. this.message[type] = this.message[type].filter(item => item !== fn)
    28. }
    29. }
    30. const res = new observer('小方')
    31. console.log('初始数据: ', res)
    32. const fnA = () => {
    33. console.log('我是张三, 我想购买这本书')
    34. }
    35. const fnB = () => {
    36. console.log('我是李四, 我想购买这本书')
    37. }
    38. const fnC = () => {
    39. console.log('我是王五, 我想购买这本书')
    40. }
    41. // 新增(留下联系方式)
    42. res.add('JS从入门到入土', fnA)
    43. res.add('JS从入门到入土', fnB)
    44. res.add('颈椎病的预防', fnC)
    45. // 书本到了, 通知对应的预约者, 前来购买
    46. res.tri('颈椎病的预防')
    47. // 某人, 取消预约一本书
    48. res.remove('JS从入门到入土', fnA)
    49. console.log(res)

  • 相关阅读:
    人类认知的贝叶斯与机器的贝叶斯
    java基于ssm的房屋租赁出租管理系统
    2023 Google 开发者大会学习心得总结
    keepalived IP漂移
    GCC 指令详解及动态库、静态库的使用
    SpringCache-缓存技术
    windows环境elasticsearch设置登录用户名、密码
    【零基础学习03】嵌入式linux驱动中自旋锁功能基本实现
    解决在选项卡中,只有默认选项里的vue-seamless-scroll可以滚动的问题
    【JAVA】栈和队列(Part1 栈)
  • 原文地址:https://blog.csdn.net/m0_58190023/article/details/128060917