常用设计模式(三)

接着之前的思路今天来介绍一下常用的设计模式有哪些

单例模式(Singleton Pattern)

又称为单体模式,保证一个类只有一个实例,并提供一个访问它的全局访问点。也就是说,第二次使用同一个类创建新对象的时候,应该得到与第一次创建的对象完全相同的对象。
比如说常见的前端的 window、document、Redux数据仓库store等…这些都是很典型的单例模式。
再比如前端常用的jquery、axios对外暴露的都是全局唯一的一个实例。

通过静态属性创建单例

class Person{
    static instance = null;
    constructor(name){
        if(Person.instance){
            return Person.instance;
        }
        Person.instance = this;
        this.name = name;
    }
}

let zhangsan = new Person("张三")
let lisi = new Person("李四")

// 虽然示例话了两次,但返回的实际是全局内的同一个
console.log(zhangsan, lisi)
console.log(zhangsan===lisi);

在这里插入图片描述

通用单例

上面的方法可以,但不够通用。比如此时有一个Person, 一个Animal的话,那就需要在每个类中都定义这么个静态属性来判断。
此时我们就可以使用工厂模式来封装判断一下

class Person{
    constructor(name){
        this.name = name;
    }
}

// 通用单例,通过闭包判断是否有已近有实例存在了
function createInstance(fn){
    let instance;
    return function(...args){
        if(!instance){
            instance = new fn(...args);
        }
        return instance
    }
}

let singlePerson = createInstance(Perosn);
let zhansan  = new singlePerson("张三");
let lisi  = new singlePerson("李四");
console.log(zhangsan, lisi)
console.log(zhansan===lisi);

在这里插入图片描述
可以看到此时的效果是一样的,但这样更加的通用,我们吧单利的判断逻辑单独的抽离出去。正常需要使用单例的class只需要通过我们提供的函数包装一下即可。

工厂模式

工厂模式 (Factory Pattern),封装具体实例创建逻辑和过程,外部只需要根据不同条件返回不同的实例。
对象的创建和实现做对应的分离,解耦了实现和创建。
可以类比下取货是从工厂取货的,货物的实现是工厂里面的工人在另外一个地方(另外的函数/类/对象)中实现的
● 优点:实现代码复用性,封装良好,抽象逻辑;
● 缺点:增加了代码复杂程度;
比如下面两个Person和Animal两个类。两个类的方法/属性都在各自的类中

class Person {
	constructor(name) {
    	this.name = name;
  }
}
class Animal {
	constructor(name) {
    	this.name = name;
  }
}

可以用一个工厂类封装类实例的创建过程, 相当于用Factory来实例出对象,把上面功能的实现给抽离出来。

function Factory(name) {
  //使用者只需要关注怎么创建/使用实例即可,具体的类的内部实现不关心 
  switch (name) {
    case 'person':
      return new Person();
      break;
    case 'animal':
      return new Animal();
      break;
    default:
      console.log("无...");
      break;
  }
}
 const person = Factory("person");
 const animal = Factory("animal");
 console.log(person,animal);

装饰者模式

装饰者模式 (Decorator Pattern)使用一种更为灵活的方式来动态给一个对象/函数等添加额外信息/功能
● 扩展功能和继承类似
● 扩展不同类的功能,和原始类并无关联;
缺点:要装饰的对象不清楚
其实就是功能的扩展,以类举例,在类中可以使用extend来继承,extend很多情况下都是在基类中去扩展一些新的功能
而装饰着模式,都是拓展一些额外的功能。
比如看下面这个demo

class Person{
    constructor(){
        this.name = "张三";
    }
    skill(){
        console.log("张三有技能.");
    }
}

let zhansan = new Person();
zhansan.skill();

function level(){
    console.log("软件开发架构师");
}
function years(){
    console.log("工作了8年");
}

Function.prototype.Decorator = function(fn){
    // 谁调用了这个Function那么this就指向谁
    let _this = this;
    // 返回一个函数(函数原型链上有Decorator)
    // 这样后面就可以接着使用Decorator了,就形成了装饰者链
    return function(){
        // yase.release()这个方法要执行
        _this(); 
        // 同时也要拓展/执行传递进来的方法
        fn();
    }
}
zhansan.skill.Decorator(level)();
// 装饰者链
zhansan.skill.Decorator(level).Decorator(years)();

定义了一个Person的类,有技能。但是我们期望在有技能的基础上新增一些功能,比如工作的年限,以及当前的水平是如何。
我们就可以使用装饰着模式来增加Person的功能
最后一次打印的日志如下:
在这里插入图片描述

观察者模式

观察者模式 (Observer Pattern) 定义一个对象与其他对象之间的一种依赖关系,当对象发生某种变化的时候,依赖它的其它对象都会得到更新。
优点:

  1. 把一个对象和另一个对象关联在一起
  2. 可以惰性执行,比如回调函数,并不会立即执行,而是被观察的对象相应的事件触发之后才会执行
  3. 可以一对多的关系

意义:做解耦,把两个类,两个对象,两个模块通过事件管理,统一去管理事件,把事件解耦

这个在平时开发中其实就有很多的应用场景。比如下面其实就是把.box这个元素观察起来,如果这个元素被点击了,就会触发对应的回调

document.querySelector(".box").addEventListener("click",function(){
    console.log("click1");
})
// 一对多的注册也ok
document.querySelector(".box").addEventListener("click",function(){
  console.log("click1");
})
document.querySelector(".box").addEventListener("click",function(){
  console.log("click2");
})

基本实现

// 先定义两个对象,将这两个对象关联起来
let obj1 = {
    fn1(){
        console.log("fn1更新");
    }
}
let obj2 = {
    fn2(){
        console.log("fn2更新");
    }
}

// 管理事件类
class MyEvent{
    constructor(){
        this.handles = {};
    }
    addEvent(eventName,fn){
        // {myevent1:[fn1,fn2...],myevent2:[fn1,fn2...]}
        if(typeof this.handles[eventName]==="undefined"){
            // 第一次没有,先初始化为一个数组
            this.handles[eventName] = [];
        }
        // 该事件对应的有一个数组事件
        this.handles[eventName].push(fn);
    }
    trigger(eventName){
        // 当前事件不在handles里面
        if(!(eventName in this.handles)){
            return ;
        }
        // 监听该事件的数组函数全部执行一遍
        this.handles[eventName].forEach(fn=>{
            fn();
        })
    }
}

// 使用
let eventObj = new MyEvent();
eventObj.addEvent("myevent",obj1.fn1);
eventObj.addEvent("myevent",obj2.fn2);

setTimeout(()=>{
    eventObj.trigger("myevent")
},1000)

代理模式

代理模式为其他对象提供一种代理以控制对这个对象的访问,类似于生活中的中介。需要对原本代理的对象做一些控制,如果不做控制的话,那就没有多大意义了

应用

  1. proxy 服务器代理 转发请求 nginx
  2. ES6 的Proxy,可以代理对象,对原本的对象做一些控制(VUE3的核心)

Demo

我们可以代理图片的展示,以实现图片懒加载的效果

class CreateImage{
    constructor(){
        this.img = document.createElement("img");
        document.body.appendChild(this.img);
    }
    setSrc(src){
        this.img.src = src;
    }
}
// 目标图片,
let src = "http2://x.x.xx.xxx";
// 代理图片的创建
function proxyImg(src){
    let myImg = new CreateImage();
    // 创建一个Img加载目标图片
    let loadImg = new Image();
    // 本地图片,加载快速
    myImg.setSrc("./loading.gif");
    // 创建的loadImg真实加载目标图片
    loadImg.src = src;
    // 目标图片加载到本地之后,再修改myImg的src
    loadImg.onload = function(){
        myImg.setSrc(src);
    }
}
proxyImg(src);

适配器模式

两个不兼容的接口之间的桥梁,将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
类似举个例子比如中国电压220v去欧洲不能正常充电,就需要一个转换器来做适配

我们在编码时最好不要过多的使用,过多的使用就会显得比较凌乱,要适度使用,使用好。
在前端axios兼容前端浏览器和node,实际上就是使用了适配器。里面有个模块专门做适配的

// 适配器模式
function getUsers(){
    return [{
        name:"yjian",
        age:21
    },{
        name:"cyril",
        age:26
    }]
}
// 如果期望返回的: // [{yjian:21},{cyril,26}]

function Adaptor(users){
    let arr = [];
    for(let i=0;i<users.length;i++){
        arr[users[i].name] = users[i].age;
    }
    return arr;
}

let res =  Adaptor(getUsers());
console.log(res);

mixin 混入模式

也是为了扩展原有对象的功能。vue2里面用的比较多

// 混入模式

// 工程师
class FrontEngineer{
    constructor(){
        this.name = "工程师";
    }
}

// 工程师的技能单独抽成一个类(除了前端工程师,其他工程师也是有技能的)
class Skills{
    code(){
        console.log("编写代码")
    }
    architect(){
        console.log("技术架构能力");
    }
    http(){
        console.log("了解http协议");
    }
}

// 目标:实例化一个工程师,工程师有技能

// 可以使用集成 比如 Skill extend FrontEngineer.
// 那技能继承工程师,当前场景需求虽然满足,但会觉得非常奇怪,技能继承于职位。而且其他职位也有技能
// js语言里面没有多继承的方式,即一个类即继承FrontEngineer,又继承Skills
// 所以就需要这种混入模式
// let engineer = new FrontEngineer();
// 混入模式,思路是 Class其实都是函数,在原型链上找到技能的函数强行混到FrontEngineer的原型链即可
function mixin(receivingClass,givingClass){
	// 后面的参数就是需要混入的函数名
    if(typeof arguments[2] !== "undefined"){
        for(let i=2;i<arguments.length;i++){
            receivingClass.prototype[arguments[i]]= givingClass.prototype[arguments[i]];
        }
    }
}

// 把Skills中的code, architect, http技能给混入到FrontEngineer中去
mixin(FrontEngineer,Skills,"code","architect","http");

let engineer = new FrontEngineer();
console.log(engineer);
engineer.architect();

在这里插入图片描述
可以看到在engineer的原型链上已近混入了code、architect、http方法

享元模式

享元模式:运用共享技术来有效地支持对象的复用,以减少创建的对象的数量。
通过共享对象节约内存资源,提高性能和效率

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

es相关的知识点

海量数据下如何提升es的操作性能 .filesystemcache os cache操作系统缓存 es中的数据,实际上写入磁盘,磁盘文件的操作系统,实际上会将数据写入到oscache中 es的搜索引擎严重依赖于底层的filesystemcache 如果filesystemcache的内存足够大,可以容纳所有的index segmentfile索引…

ABB CI546 3BSE012545R1 模块

ABB CI546 3BSE012545R1 模块. ABB CI546 3BSE012545R1 模块 电子电工技术的电力系统分析 1电子电工技能特色 电子电工技能是凭仗计算机技能开展起来的&#xff0c;并朝着智能化、网络化的方向开展。随着时代的开展&#xff0c;新式技能不断涌现&#xff0c;使传统电工技能运用…

基于 opencv 的人脸识别上课考勤系统,附源码,可作为毕业设计

一、简介 这个人脸识别考勤签到系统是基于大佬的人脸识别陌生人报警系统二次开发的。 项目使用Python实现&#xff0c;基于OpenCV框架进行人脸识别和摄像头硬件调用&#xff0c;同时也用OpenCV工具包处理图片。交互界面使用pyqt5实现。 该系统实现了从学生信息输入、人脸数据…

【微服务】SpringBoot 插件化开发模式详细总结

目录 一、前言 1.1 使用插件的好处 1.1.1 模块解耦 1.1.2 提升扩展性和开放性 1.1.3 方便第三方接入 1.2 插件化常用实现思路 二、Java常用插件实现方案 2.1 serviceloader方式 2.1.1 java spi 2.1.2 java spi 简单案例 2.2 自定义配置约定方式 2.2.1 添加配置文件…

【备战秋招】每日一题:4月15日美团春招:题面+题目思路 + C++/python/js/Go/java带注释

2023大厂笔试模拟练习网站&#xff08;含题解&#xff09; www.codefun2000.com 最近我们一直在将收集到的各种大厂笔试的解题思路还原成题目并制作数据&#xff0c;挂载到我们的OJ上&#xff0c;供大家学习交流&#xff0c;体会笔试难度。现已录入200道互联网大厂模拟练习题&a…

【深入浅出 Spring Security(九)】解决跨域问题和 Axios 所需配置

跨域 一、SpringMVC 跨域的解决方案CrossOrigin&#xff08;注解的方式解决&#xff09;addCorsMappings&#xff08;实现WebMvcConfigurer接口&#xff0c;重写方法&#xff09; 二、Spring Security 跨域的解决方案前后端跨域测试&#xff08;前端相关配置&#xff09; 啥是跨…

怎样才算一个计算机知识体系完整的毕业生

为什么突然想写这个话题呢&#xff1f; 最近有不少新关注的读者&#xff0c;在后台问&#xff1a;大学学 Java 和 C 哪个好找工作&#xff0c;学前端好还是后端好&#xff0c;该学 Vue 还是 React。。。 仿佛看到了自己当年的模样&#xff0c;所以觉得有必要单独写一篇文章&a…

【数据结构与算法】02 栈 (栈的多重含义,静态、动态数组栈(顺序栈),链式栈,双端栈,括号匹配)

一、栈的多重含义1.1 硬件栈1.2 运行时栈1.3 软件栈1.4 技术栈1.5 TCP/IP协议栈 二、数据结构中的栈2.1 概念2.2 栈的操作2.3 数组栈&#xff08;顺序栈&#xff09;2.31 数组栈特性2.32 C语言实现▶ 静态数组栈▶ 动态数组栈 2.4链式栈2.41 链式栈特性2.42 C语言实现 三、进阶…

「展会前线」易天光通信盛装亮相2023越南通讯展会

2023年6月7日&#xff0c;在历经了忙碌有序的前期准备工作后&#xff0c;易天光通信销售团队带着满满的信心踏上了越南通讯展会之旅&#xff01; “千呼万唤始出来&#xff0c;犹抱琵琶半遮面”。2023年6月8日&#xff0c;各方期待已久的2023越南通讯展会在越南胡志明市正式开…

【新版】系统架构设计师 - 系统配置与性能评价

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 系统配置与性能评价考点摘要系统性能概述性能指标性能调整阿姆达尔解决方案性能评价方法 架构 - 系统配置与性能评价 考点摘要 性能指标&#xff08;★★&#xff09;阿姆达尔解决方案&#xff…

第Y3周:yolov5s.yaml文件解读

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 ✅本周任务&#xff1a;将yolov5s网络模型中第4层的C3*2修改为C3*1&#xff0c;第6层的C3*3修改为C3*2。 简单介绍&#xff1a; YOLOv5配置了…

MapBox实现框选查询,多边形范围查询

还是老规矩先来看效果&#xff1a; mapbox官方没有为我们提供框选查询的案例&#xff0c;所以这个功能需要我们自己写。在openlayers框架中是有一个矩形范围查询的例子&#xff0c;但是在maobox没有。 那么我们就来说一下如何来做这个效果吧&#xff0c;首先这个效果可以分为两…

6道常见hadoop面试题及答案解析

Q1.什么是Hadoop&#xff1f;   Hadoop是一个开源软件框架&#xff0c;用于存储大量数据&#xff0c;并发处理/查询在具有多个商用硬件&#xff08;即低成本硬件&#xff09;节点的集群上的那些数据。总之&#xff0c;Hadoop包括以下内容&#xff1a;   HDFS&#xff08;Ha…

红外人体感应灯单片机开发方案

近来&#xff0c;红外人体感应灯受到了居家人们关注和喜爱。为此&#xff0c;宇凡微推出了一款低成本红外人体感应灯单片机方案。红外人体感应灯可应用于走廊、床边、楼梯、衣柜等地方&#xff0c;提供柔和照明作用。人来即亮&#xff0c;人走即灭&#xff0c;不受强光影响睡眠…

位姿估计 | 空间目标位姿估计方法分类总结

目录 前言位姿估计方法分类一、传统位姿估计方法1. 基于特征的位姿估计2. 基于模型的位姿估计 二、深度学习位姿估计方法 总结 前言 本文接着分享空间目标位姿跟踪和滤波算法中用到的一些常用内容&#xff0c;希望为后来者减少一些基础性内容的工作时间。以往分享总结见文章&a…

【C语言】整,浮点型数据存储,大小端。细节拉满!!

目录 一. 整型 1. C语言内置整型家族 类型的意义&#xff1a; 2.整型在内存如何存储的呢&#xff1f; 3. 原码&#xff0c;反码&#xff0c; 补码 原码 反码 补码 4. 当 整型遇上unsigned 会发生什么呢&#xff1f; 1. unsigned 与 signed 解析 2. printf 输出 有无…

【新版】系统架构设计师 - 信息安全技术基础知识

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 信息安全技术基础知识考点摘要信息安全基础知识信息安全系统的组成框架信息加密技术对称加密&#xff08;共享密钥&#xff09;非对称加密&#xff08;公开密钥&#xff09;信息摘要数字签名数字信…

IDEA安装教程2023

在本文中&#xff0c;我们将提供关于如何安装 IntelliJ IDEA 的详细步骤。如果您是初学者或只是想尝试一下 IDEA&#xff0c;我们建议您下载 Community 版。如果您需要更多高级功能&#xff0c;可以选择 Ultimate 版。 步骤一&#xff1a;下载 IntelliJ IDEA 首先&#xff0c;…

路漫漫其修远兮

其实不仅是专业&#xff0c;AI冲击波才刚刚开启&#xff0c;包括博客、自媒体作用也在大幅度下降呢。 很多人看过如下这幅图&#xff1a; 提示工程师确实是在当前大型语言模型不够完善的情况下&#xff0c;通过微调输入的方式来提高模型的性能。随着模型的迭代&#xff0c;这些…

功能测试如何转型自动化测试

在互联网行业&#xff0c;我们是那些被遗忘的技术人。 很多人都觉得&#xff0c;传统开发、运维才是技术含量的一个工作。 但是测试的入门门槛比较低&#xff0c;所做的事情相对有限&#xff0c; 这是我之前跟一些大型互联网软件测试负责人大牛们聊天的时候发现&#xff0c;…