手写JavaScript常见5种设计模式

news2024/11/30 5:53:04

想分享的几种设计模式

目前模式:工厂模式,单例模式,适配器模式,装饰者模式,建造者模式

建造者模式

简介:建造者模式(builder pattern)比较简单,它属于创建型模式的一种。

白话:4个部分:有个产品,有个工厂可以造产品,有个设计师指挥造多少,有个人想买产品。

买产品的用户不介意产品制造流程,只需要产品!

function Cola() {
    this.sugar = '50g',
    this.water = '100g'
}
function Packing() { // 第一种打包方式
    this.createPkg = function(){
        console.log('创建可乐外皮')
    }
    this.pushCola = function() {
        console.log('可乐倒进瓶子')
    }
    this.complete = function() {
        var cola = new Cola()
        cola.complete = true
        return cola
    }
    this.init = function() {
        this.createPkg() // 创建外皮
        this.pushCola() // 倒进瓶子
        //还可以增加其他步骤
        return this.complete() // 制作完成
    }
}
function greenPacking() { //绿皮可乐打包方式
    this.createPkg = function(){
        console.log('创建green可乐外皮')
    }
    this.pushCola = function() {
        console.log('可乐倒进green瓶子')
    }
    this.complete = function() {
        var cola = new Cola()
        cola.complete = true
        return cola
    }
    this.init = function() {
        this.createPkg() // 创建外皮
        this.pushCola() // 倒进瓶子
        //还可以增加其他步骤
        return this.complete() // 制作完成
    }
}
function Boss() {
    this.createCola = function(packType) {
        const pack = new window[packType]
        this.product = pack.init() //完整产品产出
    }
    this.getCola = function(packType) {
        this.createCola(packType);
        return this.product
    }
}
const boss = new Boss()
var UserCola = boss.getCola('greenPacking') // UserCola.complete === true

参考 前端进阶面试题详细解答

其他东西都不要,只要最后生产好的Cola,有sugar,有water。

关键在于Boss 函数中,担任一个整合的职责

同样的Boss函数,我可以通过更换Packing函数,打包方式,获得不同样式的Cola。

通过给getCola函数传入不同想要的参数,获得不同的最终产品。实现了可插拔的函数结构。

装饰者模式

装饰者提供比继承更有弹性的替代方案。 装饰者用用于包装同接口的对象,不仅允许你向方法添加行为,而且还可以将方法设置成原始对象调用(例如装饰者的构造函数)。

装饰者用于通过重载方法的形式添加新功能,该模式可以在被装饰者前面或者后面加上自己的行为以达到特定的目的。

好处:

装饰者是一种实现继承的替代方案。当脚本运行时,在子类中增加行为会影响原有类所有的实例,而装饰者却不然。取而代之的是它能给不同对象各自添加新行为

function iwatch () {
    this.battery = 100;
    this.getBattery = function() {
        console.log(this.battery)
    }
}

iwatch.prototype.getNewPart = function(part) {
    this[part].prototype = this; //把this对象上的属性 指向 新对象的prototype
    return new this[part]; //返回一个新对象,不修改原对象,新增了新对象的属性
}

iwatch.prototype.addNetwork = function() {
    this.network = function() {
        console.log('network')
    }
}

iwatch.prototype.addSwim = function() {
    this.swim = function() {
        console.log('swim')
    }
}

var watch = new iwatch();
watch.getBattery(); // 100

watch = watch.getNewPart('addNetwork'); // 添加新行为,network()
watch = watch.getNewPart('addSwim'); // 既有network方法,也有swim方法

在 ES7 中引入了@decorator 修饰器的提案,参考阮一峰的文章。

@testable
class MyTestableClass {
  // ...
}

function testable(target) {
  target.isTestable = true;
}

MyTestableClass.isTestable // true

直接可以使用,装饰器行为

@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A;

工厂模式

一个工厂能生产好多不同的产品,最常见的工厂函数就是jQ的$()函数,每一个函数的结果都是一个需要的产品。

function Product(name) {
  this.name = name;
}
Product.prototype.init = function () {
  console.log('init');
}
Product.prototype.go = function () {
  console.log('go');
}

function Factory () {
}
Factory.prototype.add = function(name) {
  return new Product(name);
}

//use
let f = new Factory();
let a = f.add('a');

console.log(a.name);
a.init();
a.go();

适配器模式

Adapter,将一个类(对象)的接口(方法或者属性)转化为另一个接口,以满足用户需求,使类(对象)之间接口的不兼容问题通过适配器得以解决

function Person () {
}
Person.prototype.Say = function() {
  throw new Error("该方法必须被重写!")
}
Person.prototype.Walk = function() {
  throw new Error("该方法必须被重写!")
}

function Dog () {
}
Dog.prototype.Walk = function() {
  throw new Error("该方法必须被重写!")
}
Dog.prototype.shout = function() {
  throw new Error("该方法必须被重写!")
}

function PersonA () {
  Person.apply(this)
}
PersonA.prototype = new Person()
PersonA.prototype.Say = function() {
  console.log('Person say')
}
PersonA.prototype.Walk = function() {
  console.log('Person Walk')
}

function DogBlack () {
  Dog.apply(this)
}
DogBlack.prototype = new Dog()
DogBlack.prototype.Walk = function() {
  console.log('Dog Walk')
}
DogBlack.prototype.shout = function() {
  console.log('Dog Shout')
}

//现在希望Dog类也可以学会Say,并且多走几步

function DogSayAdapter (DogClass) {
  Dog.apply(this)
  this.DogClass = DogClass
}
DogSayAdapter.prototype = new Dog()
DogSayAdapter.prototype.Say = function() {
  this.DogClass.shout()
}
DogSayAdapter.prototype.Walk = function() {
  this.DogClass.Walk()
  this.DogClass.Walk()
}

var personA = new PersonA()
var dogBlack = new DogBlack()
var dogSay = new DogSayAdapter(dogBlack)

personA.Say()
personA.Walk()
dogBlack.Walk()
dogBlack.shout()

dogSay.Say()
dogSay.Walk()//walk * 2    

适配器不只是函数接口,还有数据格式的适配

在前后端数据传递时,常用到适配器模式,也就是通俗易懂的格式化数据,format函数等等

vue的computed计算属性也是适配器模式的一种实现

const originData = [
    {
        title: 'title',
        age: 18,
        content: ['123',321],
        callback: function(){
            console.log(this)
        }
    },
  {
        title: 'title2',
        age: 1,
        content: ['1',3],
        callback: function(){
            console.log('title2')
        }
    }
]

function dataAdapter(data) {
  return data.map(item => {
    return {
      title: item.title,
      content: item.content.join(','),
      init: item.callback
    }
  })
}

var formatData = dataAdapter(originData)

e.g:原始data 的数据不满足当前的要求,通过适配器,把数据格式化成想要的格式,对原始数据没有改变

单例模式

function Simple (name) {
  this.name = name
}
Simple.prototype.go = function() {
  this.name = 'go'
  console.log(this.name)
}

//static静态方法
Simple.getInstance = (function() {
  var ins
  return function(name){
    if (!ins) {
      ins = new Simple(name)
    }
    return ins
  }
})()

let a = Simple.getInstance('a') // name: a
let b = Simple.getInstance('b') // name: a

b===a//true

非单例模式下,相同的new Simple()构造函数,不相等。

通过闭包只创建一次Simple实例,大家公用一个。

惰性单例模式

惰性和懒加载lazyload相似,延迟加载,或者说需要时再加载,不然一次加载过多,频繁进行操作dom影响性能

尽管上述代码有Simple.getInstance方法,可以在需要时再进行实例化,但仍然不是一个好的实现方式。

可以将惰性加载的部分提取出来。

e.g:

var simple = function(fn) {
    var instance;
    return function() {
        return instance || (instance = fn.apply(this, arguments));
    }
};
// 创建遮罩层
var createMask = function(){
    // 创建div元素
    var mask = document.createElement('div');
    // 设置样式
    mask.style.position = 'fixed';
    mask.style.top = '0';
      ...
    ...
    document.body.appendChild(mask);
    // 单击隐藏遮罩层
    mask.onclick = function(){
        this.style.display = 'none';
    }
    return mask;
};

// 创建登陆窗口
var createLogin = function() {
    // 创建div元素
    var login = document.createElement('div');
    // 设置样式
    login.style.position = 'fixed';
    login.style.top = '50%';
      ...
    ...
    login.innerHTML = 'login it';
    document.body.appendChild(login);

    return login;
};

document.getElementById('btn').onclick = function() {
    var oMask = simple(createMask)();
    oMask.style.display = 'block';
    var oLogin = simple(createLogin)();
    oLogin.style.display = 'block';
}

总结

对五种常见常用的设计模式进行了学习,这几种很多时候都会用到,接下来还会继续学习其他的18种设计模式,可能有的设计模式不一定在实际敲码中使用,学了没坏处,总能用得上嗷!

网上对于设计模式的文章,书籍层出不尽,但看得再多,不如自己理解,并且实际使用。很多时候是几种设计模式融合在一起使用,如果不是自己去写一遍,理解一遍,可能常见的设计模式都理解不了。这样就太可惜了,发现干净整洁的代码,都说不出哪里好,就是看着舒服,顺眼,运行速度快…

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

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

相关文章

QT入门Input Widgets之QScrollBar

目录 一、界面布局功能 1、界面位置介绍 2、控件界面基本属性 2.1 horizontalScrollBar界面属性 3、样式设置 此文为作者原创,创作不易,转载请标明出处! 一、界面布局功能 1、界面位置介绍 QScrollBar主要分为两种,一种垂直…

C语言(字符串输入)

目录 一.gets和puts组合 二.fgets()和fputs() 三.fgets()函数返回 四.fgets读取满问题 五.修改fgets函数,自动用\0替换\n 一.gets和puts组合 Gets()读取整行输入,知道遇到换行符,然后丢弃换行符,存储其余字符,并在这些字符的…

学习笔记:文件

因为有的数据,数据量极大。或者是你想把编译输出的内容存储起来,就可以使用文件 读文件中内容具体操作 来自C语言详解 FILE文件操作 - 知乎 (zhihu.com) 写入文件具体操作 同样来自 C语言详解 FILE文件操作 - 知乎 (zhihu.com) 当文件关闭时&#xff0c…

sql手工注入dvwa靶场

sql手工注入dvwa靶场 记录一下自己重新开始学习web安全之路④。 一、找交互点(url、搜索框、登录框) 在dvwa靶场中,发现有url,有搜索框。 二、找注入点(通过 ’ 号来判断) 思考一:为什么能通…

响应式圣经:10W字,实现Spring响应式编程自由

前言 全链路异步化改造的基础是响应式编程 随着业务的发展,微服务应用的流量越来越大,使用到的资源也越来越多。 在微服务架构下,大量的应用都是 SpringCloud 分布式架构,这种架构总体上是全链路同步模式。 全链路同步模式不仅…

膳食锌缺乏或过量对人体肠道菌群及健康的影响

谷禾健康 锌与肠道微生物 锌(Zn)是人体必需的微量元素,是人体中第二丰富的矿物质。锌在细胞和器官功能中起着关键的催化、调节和结构作用。 ★ 膳食锌缺乏或过量均不健康 锌缺乏与发育不良、免疫功能低下、味觉丧失、不良妊娠结局、脱发、皮肤损伤和神经行为异常有关…

数据结构 | 树 | 二叉树

🔥Go for it!🔥 📝个人主页:按键难防 📫 如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀 📖系列专栏:数据结构与算法 &#x1f52…

windows本地开发Spark[不开虚拟机]

1. windows本地安装hadoop hadoop 官网下载 hadoop2.9.1版本 1.1 解压缩至C:\XX\XX\hadoop-2.9.1 1.2 下载动态链接库和工具库 1.3 将文件winutils.exe放在目录C:\XX\XX\hadoop-2.9.1\bin下 1.4 将文件hadoop.dll放在目录C:\XX\XX\hadoop-2.9.1\bin下 1.5 将文件hadoop.dl…

Redis学习【5】之集合的底层实现原理

文章目录一 集合的底层实现原理1.1 两种实现的选择1.2 zipList【存在于Redis7.0之前的版本】1.3 listPack【Redis7.0中zipList的改进版】1.4 skipList1.4.1 skipList 原理1.4.2 skipList存在的问题与优化1.5 quickList1.5.1 quitList检索操作1.5.2 quitList插入操作1.5.3 quitL…

知识图谱概述

知识图谱 知识图谱本质上是一种大规模的语义网络,富含实体、概念及其之间的各种语义关系。 作为一种语义网络是大数据时代知识表示的重要方式之一。 作为一种技术体系,是大数据时代知识工程代表性进展。 领域知识图谱 领 域(行业&#xf…

一篇文章带你熟练使用Ansible中的playbook

目录 一、Playbook的功能 二、YAML 1、简介 2、特点 3、语法简介 4、YAML 列表 5、YAML的字典 三、playbook执行命令 四、 Playbook的核心组件 五、vim 设定技巧 练习 一、Playbook的功能 playbook 是由一个或多个play组成的列表 Playboot 文件使用YAML来写的 二、…

Mysql5.7安装【Windows版】

文章目录一、下载二、添加到环境变量三、添加配置文件my.ini四、安装Mysql 修改密码一、下载 下载地址 滑倒最下面有一个MySQL Community Server 选择要下载的版本 二、添加到环境变量 下载好了之后开始解压 把bin目录添加到环境变量 可以点击进入bin目录,直接复…

低代码平台真的是企业的福音吗?

研究低代码平台已有3年,也算是个低代码资深用户了,下面基于个人理解给大家做一份2k字的深入介绍!希望对大家在低代码方面有一定帮助。 开篇,先带大家来看企业为什么要布局低代码平台!究竟有何优势? &…

认识钉钉小程序_搭建一个简单的小程序---钉钉小程序开发教程001

其实这里面开发的时候具体,应该有很多的坑,不过..因为暂时不需要具体做,我仅仅查了一下怎么做,记录一下,以后不用再查了. 感觉钉钉小程序开发比微信小程序开发要更便捷,简单一些.首先要注册一个开发者,其实登录上钉钉账号就可以了.然后可以看看,快速入门,我没看 然后下载开发工…

Java基础之多线程JUC全面学习笔记

目录初识多线程多线程的实现方式常见的成员方法线程安全的问题死锁生产者和消费者线程池自定义线程池初识多线程 什么是多线程? 线程 线程是操作系统能够进行运算调度的最小单位。线程被包含在进程之中,是进程中的实际运作单位。 简单理解:应用软件中互相独立&…

为什么西门子、美的等企业这样进行架构升级,看看改造效果就知道了

在工业领域, 生产、测试、运行阶段都可能会产生大量带有时间戳的传感器数据,这都属于典型的时序数据。时序数据主要由各类型实时监测、检查与分析设备所采集或产生,涉及制造、电力、化工、工程作业等多个行业,具备写多读少、量非常…

从端到端打通模型端侧部署流程(NCNN)

文章目录背景介绍:为什么要做端侧推理:端侧深度学习部署流程:一条主要技术路线:ONNX:NCNN框架:NCNN的官方介绍:NCNN问题解决:NCNN使用样例快速在NCNN框架下验证自己的模型&#xff1…

数据分析思维(六)|循环/闭环思维

循环/闭环思维 1、概念 在很多的分析场景下,我们需要按照一套流程反复分析,而不是进行一次性的分析,也就是说这套流程的结果会成为该流程的新一次输入,从而形成一个闭环,此时的分析思维我们称之为循环/闭环思维。 常…

计算机断层扫描结肠镜和全自动骨密度仪在一次检查中的可行性

计算机断层扫描结肠镜和全自动骨密度仪在一次检查中的可行性 Feasibility of Simultaneous Computed Tomographic Colonography and Fully Automated Bone Mineral Densitometry in a Single Examination 简单总结: 数据:患者的结肠镜检查和腹部CT检查…

2022黑马Redis跟学笔记.实战篇(三)

2022黑马Redis跟学笔记.实战篇 三4.2.商家查询的缓存功能4.3.1.认识缓存4.3.1.1.什么是缓存4.3.1.2.缓存的作用1.为什么要使用缓存2.如何使用缓存3. 添加商户缓存4. 缓存模型和思路4.3.1.3.缓存的成本4.3.2.添加redis缓存4.3.3.缓存更新策略4.3.3.1.三种策略(1).内存淘汰:Redis…