JS - 设计模式持续学习中

news2024/11/24 0:30:10

通过例子持续学习JS设计模式中,接下来请跟随我的步伐走进我的学习笔记世界~

什么是设计模式?我们为什么需要学习设计模式?

设计模式是可以更好解决问题的一种方案。

这意味着什么?如果你开发的项目的功能是固定的,永远不会调整业务,那么你就不需要使用设计模式等任何技巧。您只需要使用通常的方式编写代码并完成需求即可。

但是,我们的开发项目的需求是不断变化的,这就需要我们经常修改我们的代码。也就是说,我们现在写代码的时候,需要为未来业务需求可能发生的变化做好准备。

这时,你会发现使用设计模式可以让你的代码更具可扩展性。

1 命令模式

  • 我的理解
    定义一个类,里面写方法,用的时候引入这个类,调用类.方法()使用。

  • 定义
    有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁。此时希望用一种松耦合的方式来设计程序,使得请求发送者请求接收者能够消除彼此之间的耦合关系。
    在这里插入图片描述

  • 适用场景:绘制按钮,不知道某个按钮未来将用来做什么,可能用来刷新菜单界面,也可能用来增加一些子菜单,只知道点击这个按钮会发生某些事情。那么当完成这个按钮的绘制之后,应该如何给它绑定onclick 事件呢? 我们很快可以找到在这里运用命令模式的理由:点击了按钮之后,必须向某些负责具体行为的对象发送请求,这些对象就是请求的接收者。但是目前并不知道接收者是什么对象,也不知道接收者究竟会做什么。此时我们需要借助命令对象的帮助,以便解开按钮和负责具体行为对象之间的耦合。

const btn1 = function () {};
const btn2 = function () {};

// 定义一个命令发布者的类
class Executor {
    setCommand(btn, command) {
        btn.onclick = function() {
            command.execute()
        }
    }
}

// 定义一个命令接收者
class Menu {
    refresh() {
        console.log('刷新菜单')
    }

    addSubMenu() {
        console.log('增加子菜单')
    }
}

// 定义一个刷新菜单的命令对象的类
class RefreshMenu {
    constructor(receiver) {
        // 命令对象与接收者关联
        this.receiver = receiver
    }

    // 暴露出统一的接口给命令发布者Executor
    execute() {
        this.receiver.refresh()
    }
}

// 定义一个增加子菜单的命令对象的类
class AddSubMenu {
    constructor(receiver) {
        // 命令对象与接收者关联
        this.receiver = receiver
    }
    // 暴露出统一的接口给命令发布者Executor
    execute() {
        this.receiver.addSubMenu()
    }
}

var menu = new Menu()
var executor = new Executor()

var refreshMenu = new RefreshMenu(menu)
// 给按钮1添加刷新功能
executor.setCommand(btn1, refreshMenu)

var addSubMenu = new AddSubMenu(menu)
// 给按钮2添加增加子菜单功能
executor.setCommand(btn2, addSubMenu)

// 如果想给按钮3增加删除菜单的功能,就继续增加删除菜单的命令对象和接收者的具体删除方法,而不必修改命令对象
btn1.onclick();
btn2.onclick();

2 单例模式

  • 定义
    保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。
  • 适用场景
    一个单一对象。比如:弹窗,无论点击多少次,弹窗只应该被创建一次。
class CreateUser {
    constructor(name) {
        this.name = name;
        this.getName();
    }
    getName() {
         return this.name;
    }
}
// 代理实现单例模式
var ProxyMode = (function() {
    var instance = null;
    return function(name) {
        if(!instance) {
            instance = new CreateUser(name);
        }
        return instance;
    }
})();
// 测试单体模式的实例
var a = new ProxyMode("aaa");
var b = new ProxyMode("bbb");
// 因为单体模式是只实例化一次,所以下面的实例是相等的
console.log(a === b);    //true

3 策略模式

  • 定义
    定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。
    策略模式的目的就是将算法的使用和算法的实现分离开来。
  • 适用场景
    如果您的函数具有以下特征:判断条件很多;各个判断条件下的代码相互独立。然后,你可以将每个判断条件下的代码封装成一个独立的函数,接着,建立判断条件和具体策略的映射关系,使用策略模式重构你的代码。
/** 假设您目前正在从事一个电子商务商店的项目。
* 每个产品都有一个原价,我们可以称之为 originalPrice。
* 但并非所有产品都以原价出售,我们可能会推出允许以折扣价
* 出售商品的促销活动。商家可以在后台为产品设置不同的状态。
* 然后实际售价将根据产品状态和原价动态调整。 
* 具体规则:xxxxxxxxx;
* 如果你需要写一个getPrice函数,你应该怎么写呢?*/

let priceStrategies = {
  'pre-sale': preSalePrice,
  'promotion': promotionPrice,
  'black-friday': blackFridayPrice,
  'default': defaultPrice
}

function getPrice(originalPrice, status) {
  return priceStrategies[status](originalPrice)
}

function blackFridayPrice(origialPrice) {
  if (origialPrice >= 100 && originalPrice < 200) {
    return origialPrice - 20
  } else if (originalPrice >= 200) {
    return originalPrice - 50
  } else {
    return originalPrice * 0.8
  }
}

function defaultPrice(origialPrice) {
  return origialPrice
}

function getPrice(originalPrice, status) {
  if (status === 'pre-sale') {
    return preSalePrice(originalPrice)
  }

  if (status === 'promotion') {
    return promotionPrice(originalPrice)
  }

  if (status === 'black-friday') {
    return blackFridayPrice(originalPrice)
  }

  if(status === 'default'){
    return defaultPrice(originalPrice)
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1326534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法通关村第十四关—堆结构(青铜)

堆结构 一、堆的概念和特征 堆是将一组数据按照完全二叉树的存储顺序&#xff0c;将数据存储在一个一维数组中的结构。堆有两种结构&#xff0c;一种称为大顶堆&#xff0c;一种称为小顶堆&#xff0c;如下图。 1.小顶堆&#xff1a;任意节点的值均小于等于它的左右孩子&#…

android 新版studio gradle 里面没有offline 勾选项

studio 右边 gradle 上面有个图标可以点击切换

宏基因组学中基于Kraken2、Blast、ViPhOG和VirSorter等工具分析病毒组的详细流程,包括数据预处理、病毒序列检测、分类和功能注释等步骤

宏基因组学中分析病毒组的详细流程&#xff0c;包括数据预处理、病毒序列检测、分类和功能注释等步骤。 示例代码使用了常用的生物信息学工具&#xff0c;如Kraken2、Blast、ViPhOG和VirSorter等。 1. 数据预处理 质量控制&#xff1a; 使用FastQC进行原始测序数据的质量检查…

机器视觉:AI赋能缺陷检测,铸就芯片产品的大算力与高能效

导言&#xff1a;近年来&#xff0c;国内芯片行业快速发展&#xff0c;市场对芯片需求的不断增大&#xff0c;芯片的缺陷检测压力也越来越大。芯片产品在生产制造过程中&#xff0c;需要经历数道工序&#xff0c;每个生产环节的材料、环境、工艺参数等都有可能造成产品缺陷。不…

低代码:万事俱备,就差一个程序员

前言 低代码技术&#xff0c;作为当前软件开发领域的一颗新星&#xff0c;正在逐渐改变着传统编程的面貌。其核心特点鲜明且富有创新性&#xff0c;如通过直观的拖拽组件来进行软件开发&#xff0c;这种方式极大地降低了编程的复杂性。可视化编程则是将复杂的代码逻辑转化为图…

js 图片 手动上传,并回显

效果展示&#xff1a; 代码&#xff1a; <label for"avatarUpload"><div><img v-if"avatatImageUrl" :src"avatatImageUrl" class"avatar"><img v-else src"../../assets/images/account/avatar-upload.png…

20231221将NanoPC-T4(RK3399)开发板适配Android12的挖掘机并打开AP6398SV

20231221将NanoPC-T4(RK3399)开发板适配Android12的挖掘机并打开AP6398SV 2023/12/21 17:46 SDK使用&#xff1a;rk356x_android12_220722.tgz android12-rk3588-new_20221229_1732toybrick.tgz【TB3588X】 1、【必须更换AP6398SV征集的驱动程序&#xff01;】 Z:\3TB\91rk_an…

Elasticsearch 性能调优基础知识

Elastic Stack 已成为监控任何环境或应用程序的实际解决方案。 从日志、指标和正常运行时间到性能监控甚至安全&#xff0c;Elastic Stack 已成为满足几乎所有监控需求的一体化解决方案。 Elasticsearch 通过提供强大的分析引擎来处理任何类型的数据&#xff0c;成为这方面的基…

Vuex的学习-3

基于Vuex的案例todos&#xff0c;篇幅有点长&#xff0c;可以根据目录将会的地方可以跳过 初始化项目 1.通过vue ui 命令打开可视化面板&#xff0c;创建新项目 2.安装vuex依赖包 3.实现Todos基本布局 课程代码在此&#xff0c;直接复制即可 main.js import Vue from vue …

Seata中AT模式的实现原理02-RM分支事务提交

前言 RM是资源的管理者 处理分支事务的开启和提交回滚 当TM注册完全局事务之后进行分支事务的提交 RM一阶段处理本地事务&#xff0c;主要是在DataSource、Connection、Statement上做文章。 DataSource 创建 项目启动的时候SeataAutoDataSourceProxyCreator为所有DataSource…

通讯录应用程序开发指南

目录 一、前言 二、构建通讯录应用程序 2.1通讯录框架 (1)打印菜单 (2) 联系人信息的声明 (3)创建通讯录 (4)初始化通讯录 2.2功能实现 (1)增加联系人 (2)显示联系人 (3)删除联系人 (4)查找联系人 (5)修改联系人 (6)排序联系人 三、通讯录的优化 3.1 文件存储 …

RUST与RUSTful简介

RUST与RUSTful 1、背景2、RUST的起源3、RUST与RUSTful4、总结 1、背景 随着互联网&#xff08;Internet&#xff09;的发展&#xff0c;越来越多的人开始意识到&#xff0c;网站即软件&#xff0c;而且是一种新型的软件。这种"互联网软件"采用客户端/服务器&#xff…

el-table设置默认选中报错_this.$refs.singleTable.toggleAllSelection is not a function

直接使用以下的方法&#xff0c;报错信息是_this.$refs.singleTable.toggleAllSelection is not a function this.$refs.singleTable.toggleAllSelection()看了网上的解决方法&#xff0c;加了this.$nextTick,代码如下&#xff0c;但还是报错Error in nextTick: "TypeErr…

ubuntu部署llama2-chinese

ubuntu上安装cuda见之前的blog&#xff0c;已安装cuda12&#xff0c;使用nvcc-V 下载llama2-chinese&#xff1a;GitHub - FlagAlpha/Llama2-Chinese: Llama中文社区&#xff0c;最好的中文Llama大模型&#xff0c;完全开源可商用 conda create -n llamachinese python3.10 pi…

构建高效的研发管理体系

目录 一、什么是研发管理体系 二、研发管理体系有哪些 1、 基于CMMI的研发体系 ​2、基于IPD的研发体系 3、 基于敏捷模式的研发体系 三、研发管理的痛点 四、如何构建高效的研发管理体系 一、什么是研发管理体系 研发管理就是在研发体系结构设计的基础之上&#xff0…

[网络安全]在win2000虚拟机上创建隐藏账户

目录 1.winR->cmd->regedt32 2.新建账号&#xff0c;例如HiddenAccount$($表示在命令行下不现实此用户&#xff09; 3.winR->cmd->regedit 3.将HiddenAccount$删掉 4.最后一步 手工创建隐藏账户 1.你需要一台win2000 2.winR->cmd->regedt32 增加HEY_LOAC…

3A服务器 (hcia)

原理 认证&#xff1a;验证用户是否可以获得网络访问权。 授权&#xff1a;授权用户可以使用哪些服务。 计费&#xff1a;记录用户使用网络资源的情况 实验 步骤 1.配置ip地址 2.配置认证服务器 aaa authentication-scheme datacom&#xff08;认证服务器名字&#xf…

21 Vue3中使用v-for遍历对象数组

概述 使用v-for遍历对象数组在真实的开发中也属于非常常见的用法&#xff0c;需要重点掌握。 因为目前流行的是前后端分离开发&#xff0c;在前后端分离开发中&#xff0c;最常需要处理的就是对象数组类型的数据了。 比如&#xff0c;将员工信息渲染到表格中。 这节课我们就…

如何建立一套完整的私域运营体系?

所有人都告诉你&#xff0c;今年必须做私域&#xff0c;但从没有人说清楚怎么做私域。你以为做私域就像瑞星咖啡一样&#xff0c;随便拉个群、发发券就能年入100个小目标。或者你认为最后还是微商最有效&#xff0c;每天狂刷100条朋友圈。但这样的私域一定活不过30天。因为没有…

回顾丨2023 SpeechHome 第三届语音技术研讨会

下面是整体会议的内容回顾&#xff1a; 18日线上直播回顾 18日上午9:30&#xff0c;AISHELL & SpeechHome CEO卜辉宣布研讨会开始&#xff0c;并简要介绍本次研讨会的筹备情况以及报告内容。随后&#xff0c;CCF语音对话与听觉专委会副主任、清华大学教授郑方&#xff0c…