设计模式

day24 设计模式

回顾

ajax

ajax 是一个异步请求工具,主要提供对应的客户端和服务端之间的数据交互。它可以完成对应的局部刷新(同步加载页面整体会刷新,异步加载对应的页面不会进行刷新)核心对象 (XMLHttpRequest)

ajax的流程

  • 创建xhr

  • 打开链接

  • 设置请求头(post请求)

  • 发送请求

  • 监听事件接收数据

get请求

get请求 数据携带在对应的url中

post请求

post需要设置对应的请求头 携带在请求体中

JSONP

解决对应的跨域的方案(主要利用script标签不受跨域的影响 通过回调函数来接收对应的数据)

步骤

准备一个回调函数

使用script标签链入对应的地址 传入参数及回调函数

加载完成 删除对应的script标签

设计模式

概述

设计模式是对应的一些处理方案形成的思想来构成的模式。主要针对的是类和对象的设计和构造。他不区分语言,共23总设计模式(主要用于 架构设计 和 源码设计)

设计模式的分类

  • 创建型模式 (关于对应的创建)

  • 结构型模式 (将多个小结构并入一个大结构)

  • 行为型模式 (关于对象的行为处理)

设计模式分类图

image-20230309102609834

设计模式的七大原则

  • 单一责任原则 一个类只负责一个功能领域中的相应职责,或者说一个类应该只有一个变化的原因

  • 开闭原则 一个软件实体, 如类, 模块, 函数等应该对扩展开放, 对修改封闭.

  • 里氏置换原则 子类型(subtype)必须能够替换掉他们的基类型(base type)

  • 依赖倒转原则 高层模块不应该依赖低层模块,二者都应该依赖其抽象 抽象(接口/抽象类)不应该依赖细节(类),细节应该依赖抽象

  • 接口隔离原则 接口尽量细化,接口中的方法尽量少

  • 迪米特法则 如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

  • 合成复用原则 它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

创建型模式(工厂模式、单例模式)

工厂模式

以工厂的形式来生产对象(不关注对象的细节)

function factoly(){
// 创建对象
let obj={}
// 属性赋值
obj.name=name
// 返回对象
return obj
}

单例模式(懒汉、饿汉)

保证产生的对象只有一个(不会被污染)

// 利用闭包实现
function singleton(){
   let only = null
retutn function(){
       // 判断对象是否是null
       // 如果为null产生新的对象
       if(!only){
           only=new Object()
      }
       return only
  }
}
let onlyFN = singleton()
        let obj = onlyFN()
        let obj2=onlyFN()
        console.log(obj == obj2)// true

// 利用原型来实现
function singletonProto(){
   // 判断是否存在该对象
   if(!Object.prototype.single){
       Object.prototype.single = new Object()
  }
   return Object.prototype.single
}
let onlyFN = singletonProto()
       let obj = singletonProto()
       console.log(obj == onlyFN)// true

// 利用静态属性实现
function singletonStatic(){
   if(!Object.single){
       Object.single = new Object()
  }
   return Object.single
}
let onlyFN = singletonStatic()
       let obj = singletonStatic()
       console.log(obj == onlyFN)// true

// 使用global对象实现
function singletonGlobal(){
   if(!globalThis.single){ // globalThis 这里指向是window
       globalThis.single = new Object()
  }
   return globalThis.single
}
let onlyFN = singletonGlobal()
       let obj = singletonGlobal()
       console.log(obj == onlyFN)// true

 

结构型模式(代理模式、装饰器模式、组合模式)

组合模式

将多个小结构组合成一个大结构

function playgame(){
this.init=()=>{
console.log('开机')
}
}
function Gohome(){
this.init=()=>{
console.log('回家')
}
}
function Run(){
this.init=()=>{
console.log('洗脚')
}
}
// 洗脚回家打游戏
new Run().init()
new Gohome().init()
new playgame().init()

将init 方法一起执行 利用组合模式来执行多个同名方法

function combination(){
   this.objs=[]
// 传入对应的对象数组
this.add= function(...objs){
this.objs.concat([...objs])
}
// 执行对应的里面的init方法 以参数传递函数名的方式来执行
this.exec = function (fnName){
this.objs.forEach((obj)=>{
// 调用对应的方法
obj[fnName].call(this)
})
}
}
let combination=new combination()
combination.add(new Run(),new Gohome())
combination.exec('init')

组合模式的应用 vue 里面use 和 install

image-20230309114445249

class Vue {
           // 解析对应的对象 执行对应的install
           static use(...objs) {
               obj.map(v => {
                   if (!v.install) {
                       if (typeof v != 'function') {throw new Error }
                       let fn=v
                       v = {
                           install() {
                               fn()
                          }

                      }
                  }
                   return v
              })
               Vue.exec(objs)
          }
           // 传入对象进行执行
           static exec(arr) {
               arr.forEach((obj) => {
                   obj['install'].call(this)
              })
          }
      }

装饰器模式

用一个新的类将对应的原本的对象进行包装在进行加强(在不改变原对象的基础上进行增强)

image-20230309143351091

function person(){
this.run = function(){
console.log('跑')
}
}
// 先传入要增强的对象 返回一个新对象
function stronger(){
this.person = person
this.fly = function(){
this.person.run()
console.log('我会飞')
}
}
let person=person()

ts内置有对应的装饰器 Decorator TS 中使用注解来进行对应的装饰器添加@decorator

代理模式

代理模式是在原有对象的基础上增强对应的对象(利用代理对象来增强)代理对象通常访问的是实际对象

示例

我(原本对象)请了秘书(代理),秘书给我管钱(功能增强),当秘书(代理)把钱花完了(我(原本对象)的前也没有了)

  • 代理对象对原本的对象进行了功能增强

  • 代理对象影响的是实际的对象

ES7新增了Proxy的类 来帮助我们进行代理

Proxy(VUE3的底层实现)

实例化(传入对应的被代理对象 处理对象 产生一个代理对象)

var proxy = new Proxy(target,handler)

示例

// 被代理对象
var object = {name:'张三',age:18}
// 代理对象 传入被代理对象 处理对象
var proxy=new Proxy(object,{
// 获取属性名 代理对象 被代理对象
get(targetObj, attributeName, proxyObj){

},
//设置相关的属性 属性名 代理对象 被代理对象 处理对象
set(targetObj, attributeName, attributeValue, proxyObj){

},
   // 目标对象 对应的属性 默认返回false 使用in关键词
has(target,p){
return p in target
},
   deleteProperty(targetObj, attribute){
       delete targetObj[attribute]
  }
})

proxy的handler相关属性

行为型模式(观察者模式)了解(访问者模式、解释器模式)

观察者模式

观察者模式是前端最常用的模式,它相当于对应的监听和处理执行的机制。观察者模式别名observer 又被称为发布者订阅者模式

常见的发布订阅者模式

addEventListener(事件监听器)

// box.addEventListener(事件名,handler)
box.addEventListener('click',function(){
console.log('点击了')
})
  • 你 发布者(box添加点击事件)

  • js事件处理引擎 订阅者(添加事件监听 保持监听)

  • 处理 处理函数 订阅者(订阅者进行处理)

image-20230309160912592

实现一个发布者订阅者模式

模仿EventListener来实现

  • 事件监听

  • 事件执行

  • 事件取消

class Observer {
constructor() {
// 存储事件的容器和处理函数的容器
this.events = {}
}
// 监听事件传入一个事件名和对应的处理函数
on(eventName, handler) {
// 判断是否存储了对应的事件 如果存储了就加到数组内
if (eventName in this.events) {
this.events[eventName].add(handler)
} else {
// 使用set保证没有重复
this.events[eventName] = new Set([handler])
}
}
// 执行对应的处理函数 传入对应的事件 执行对应的处理函数 传入对应的参数传给处理函数
emit(eventName,...args) {
// 不存在 跳出
if(!this.events[eventName]) return;
// 存在 遍历对应的集合 调用的对应的处理函数
this.events[eventName].forEach((handler)=>{
handler.apply(this,args)
})
}
// 移除事件监听
off(eventName,handler) {
// 查询是否具备对应的事件
// 不具备 跳出
if(!this.events[eventName]) return;
// 具备 删除
// 遍历对应的处理函数数组
this.events[eventName].delete(handler)
}
}

总结

  • off是用于取消事件

  • on 是用于监听事件

  • emit是用于执行事件

  • 存储使用的对象进行存储

  • emit传入的参数可以被处理函数接收

  • 观察者模式是vue2底层实现之一 (对应的数据双向绑定 必须使用观察者模式)

posted @ 2023-03-15 19:58  ·阿皓  阅读(121)  评论(0)    收藏  举报