day24 设计模式

设计模式

概述:

设计模式是一种固定解决某个问题的一种方式,他是同一个固定模式(原理都是一样的),他不区分语言.常用的设计模式有23钟,他分为三类(主要针对类和对象)

设计模式分类

  • 创建型(创建对象) 单例模式 工厂模式
  • 结构型(将多个小结构变成一个大结构)组合模式 代理模式 装饰器模式 适配器模式
  • 行为型 (主要对应类和对象的行为进行相关处理) 观察者模式

在这里插入图片描述

  • 开闭原则
  • 里式置换原则
  • 单一原则
  • 依赖倒置原则
  • 接口隔离原则
  • 迪米特原则
    工厂模式讲解
function factory(name){
	//手动构建对象
	var obj = new  Object()
	//给对象进行赋值
	obj.name=name
	手动返回对象
	return obj
}
//调用工厂生产对象
let obj1 =factory('tom')
let obj2 =factory('哈哈')

单例模式

  • 保证生成的对象实例只有一个

闭包实现

//基础类
class Person {
	constructor(){

	}
}
//闭包的单例模式
function closureSingleton(){
	//接收返回对象的变量
	var  newPerson =null
	return function(){
	//如果当前的变量值为null
	if(!newPerson){
	//构建一个对象赋值给返回的变量
	newPerson = new Person()
		}
	return  newPerson
	}
}
let single = closureSingleton()
let person1 = single ()
let person2 = single()
console.log(person1==person2)

静态属性

function staticSingleton(){
	if(!staticSingleton.newPeson){
		staticSingleton.newPeson = new Person()
}
	return staticSingleton.newPeson 
}
let person3 =staticSingleton()
let  person4 = staticSingleton()
console.log (person3=person4)

原型的单例

function  prototypeSingleton(){
	if(!prototypeSingleton.prototype.instance){
	prototypeSingleton.prototype.instance = new Person()
}
	return  prototypeSingleton.prototype.instance
}
let person5 = prototypeSingleton()
let person6 =prototypeSingleton()
console.log(person5==person6)

全局属性实现
window是浏览器global对象 但是其他的global对象不是window

function globaSingleton(){
	if(!window.instance){
			window.instance= new Person()
	}
	return  window.instance
}
let person7 = globaSingleton()
let person8 = globaSingleton()
console.log(person7==person8)

组合模式(☆)

  • 将多个对象的相同方法或属性组合到一块(将不同的方法组合在一块执行)

基础内容

 class GoToHome{
            constructor(){
                this.action = ()=>{
                    console.log('回家');
                }
            }
        }
        class OpenComputer{
            constructor(){
                this.action=()=>{
                    console.log('打开电脑');
                }
            }
        }
        class PlayGame{
            constructor(){
                this.action=()=>{
                    console.log('玩游戏');
                }
            }

        }
        new GoToHome().action()
        new OpenComputer().action()
        new PlayGame().action()

将多个方法组合在一块进行统一调用

 //组合模式
        class Combiner{
            constructor(){
                this.list=[]
            }
            //将对应的对象加入到list
            abc(obj){
                this.list.push(obj)
            }
            //统一执行相关函数
            execute (fn,...arg){
                //遍历list
                this.list.forEach((item)=>[
                    item[fn].call(this,...arg)
                ])
            }
        }
        let combiner= new Combiner()
        combiner.abc(new GoToHome())
        combiner.abc(new OpenComputer())
        combiner.abc(new PlayGame())
        combiner.execute('action')

组合模式在Vue中的使用

  • vue.use方法(自动执行install)
  • install 方法
  • 如果在use里面传入的是一个函数 那么他会直接把这个函数当成install 如果传的是对象 他会自动去找里面的install方法
    在这里插入图片描述

模拟实现use和install

class Vue {
    constructor() {
        this.fnList = []
    }
    use(obj) {
        //如果他是一个函数 那么这个函数直接当成install
        if (typeof obj == 'function') {
            this.fnList.push(obj)
        }
        //如果他是对象就找里面的install
        if (typeof obj == 'object') {
            this.fnList.push(obj.install)
        }
        //调用执行
        this.execute()
    }
    execute() {
        //遍历对应的函数列表
        this.fnList.forEach((fn) => {
            fn()
        })
    }
}
var vue = new Vue()
vue.use({
    install() {
        console.log('你好')
    }
})
vue.use({
    install() {
        console.log('世界')
    }
})
vue.use(() => {
    console.log('哈哈哈哈')
})

装饰器模式

场景
我现在有三个车的类,这个三个车他都有对应的跑的方法,现在我需要给这个三个车加一个飞的方法(设计模式开闭原则,一个类一旦写完了不允许内部再进行修改),这个时候就可以使用对应的装饰器模式。

概述
装饰器模式是在不影响原本类的基础上,进行功能扩展.他又叫做包装模式.
在这里插入图片描述
实现
基础类

  class Car{
        constructor(){
        }
        run(){
            console.log('跑');
        }
       }

包装类

 class Decoator{
            constructor(aa){
                this.car=aa
            }
            fly(){
                console.log('飞');
                this.car.run()
            }
       }
      
       var decoator = new Decoator(new Car())
       decoator.fly()
       console.log(decoator)
    //    new Decoator(new Car()).fly()

在typeScript中有个对应的装饰器修饰@Decorator

观察者模式(☆)

概述:
观察者模式是前端最常用的模式,他又被称为发布者-订阅者模式.他的核心就是一个对应的发布者进行发布,以及对应的订阅者(对发布的内容进行监听),发布者将对应的内容发布,订阅者收到信息从而进行对应的处理.
示例

  • 李丹喜欢看女主播(他关注一个女主播 冯提莫)
  • 冯提莫开播(发布) ----- 李丹收到开播信息 (订阅)----- 李丹就去看(处理)
  • 发布者 冯提莫
  • 订阅者 李丹
  • 处理 去直播间

发布者模式的核心内容

  • 发布者
  • 订阅者
  • 相关处理

事件就是一个观察者模式(事件发布者 事件监听者 事件处理)

element.addEventListener('事件名',处理函数)
element.removeEventListener('事件名',处理函数)

简单的事件示例

<button>点我</button>
<script>
let btn = document.querySelector('button')
btn.addEventListener('click',handler)
function handler(){
	console.log('点击了')
}
</script>
  • 发布者 button
  • 订阅者 JavaScript引擎
  • 处理 handler
分析这个事件的相关内容
  • 发布者
  • 事件名
  • 处理函数
相关关系
  • 事件名和处理函数的关系 一对多 (一个事件可以有多个处理函数)click:[handler1,handler2]
  • 发布者和事件名的关系 一对多 (一个发布者可以发布多个事件) {事件名:[处理函数]}
根据对应的事件监听机制来模拟观察者
事件监听的过程
  • 事件发布 (有对应的事件名)on
  • 事件执行 (根据对应的事件名执行相关的处理函数) emit
  • 事件取消 (将对应的事件移除)off

代码构建

class obServer{
	constructor(){
        //{click:[handler1,handler2],mousemove:[handler1,handler2]}
		this.obj = {}
	}
	//事件发布 事件名  处理函数
	on(eventName,handler){
		
	}
	//事件执行 事件名  参数
	emit(eventName,...arg){
	
	}
	//事件取消 事件名  处理函数
	off(eventName,handler){
		
	}
}

代码完善

class ObServer{
	constructor(){
        //{click:[handler1,handler2],mousemove:[handler1,handler2]}
		this.obj = {}
	}
	//事件发布 事件名  处理函数
	on(eventName,handler){
		//判断这个eventName是否存在
        //如果当前的事件名不存在 给他赋值一个空数组
        if(!this.obj[eventName]){
            this.obj[eventName] = []
        }
        //将事件添加进去
        this.obj[eventName].push(handler)
	}
	//事件执行 事件名  参数
	emit(eventName,...arg){
        //判断这个eventName是否存在
		if(!this.obj[eventName]) return
        //获取这个事件里面所有的处理函数 执行这些处理函数
        //遍历对应的处理函数数组
        this.obj[eventName].forEach(handler=>{
            //执行对应的处理函数 传入参数
            handler.call(this,...arg)
        })
	}
	//事件取消 事件名  处理函数
	off(eventName,handler){
		//判断这个eventName是否存在
		if(!this.obj[eventName]) return
		//遍历对应的eventName里面处理函数数组 找到匹配的handler将他删除
		this.obj[eventName].forEach((v,i)=>{
			if(Object.is(v,handler)){
				this.obj[eventName].splice(i,1)
			}
		})
	}
}
注意事项
  • emit执行他可以传参传给对应的on方法里面处理函数(vue中父传子的实现及bus传值的实现)
  • off调用一定要emit之前
  • 观察者模式是vue2底层实现

代理模式(☆)

概述:

在不改变原本的类的基础上,对于对象功能加强,代理模式代理出来的是对象.(代理模式低耦合)
示例

  • 你家里需要装修,但你不想动手 这个时候你就会找一个装修队(代替你装修)
  • 代理对象和被代理对象是两个不同的对象,但是实际操作的内容是一个

核心关键词

  • 对代理对象 你
  • 代理对象 装修对象
  • 操作内容 你的房子

代理的实现
在js中es7新增了一个Proxy的类 ,这个类专门用来做代理.

Proxy的使用
新建的代理对象(通过proxy的构造)

let proxy = new Proxy(被代理对象,处理对象)

基础使用

//被代理对象
let obj = {
    name: 'jack',
    age: 18
}
//通过proxy来新建代理对象 
//Proxy的构造函数需要传入被代理对象 以及相关的处理对象
//对于handler他是对于所有的属性进行操作
//get在获取属性的时候调用  他返回的结果就是你接收的结果
//set对于设置属性的时候调用
let proxy = new Proxy(obj,{
    //目标对象(被代理对象) 属性(实际访问的属性)  代理对象(当前proxy)
    get(target,attribute,proxyObj){ //这个里面返回的值就是当前的获取值
        console.log('调用了get');
        if(attribute == 'name'){
            return '姓名为'+target[attribute] 
        }else if(attribute == 'age'){
            return target[attribute]+'岁'
        }
        return target[attribute] 
    },
    //目标对象(被代理对象) 属性(实际访问的属性)值 代理对象(当前proxy)
    set(target,attribute,value,proxyObj){
        console.log('调用了set');
        target[attribute] = value
    },
    //定义属性 赋值新的属性  目标对象  属性名  属性的详情信息
    defineProperty(target,attribute,descriptor){
        console.log('新的属性定义');
    },
    //删除属性 delete的时候
    deleteProperty(target,attribute,proxyObj){
        console.log('删除属性');
        delete target[attribute]
    }
})

proxy的处理对象的四大属性

  • get 访问属性的时候调用
console.log( proxy.name); //调用get
console.log( proxy.age); //调用get
  • set 设置属性的时候调用
proxy.name = '你好' //调用set
  • defineProperty 定义属性的时候调用
Object.defineProperty(proxy,'sex',{
    configurable:true,//是否可以删除
    enumerable:true,//是否可以遍历
    value:'男',//属性值
    writable:true//是否可以改变
})
  • deleteProperty 删除属性的时候调用
delete proxy.name //调用deleteProperty

总结

  • proxy是一个es7新增的一个类,他返回的是提个对象
  • proxy里面传入被代理对象和对应的处理对象
  • 处理对象的4个方法(get set defineProperty deleteProperty)
  • proxy里面实际操作的是被代理对象 (如果在里面操作对象会)
  • 代理对象和被代理对象不是一个对象 但是操作的内容是一个都是被代理对象
  • proxy是vue3的底层实现之一

适配器模式

概述
将旧的的内容进行新的适配,在原本的基础上做兼容处理。

常用的业务场景

  • 旧的接口替换新的接口 (在不改变原本内容的情况下完成替换)
  • 表单验证(根据场景切换相关的验证)
示例
  • 家庭用电最大的功率为22v
  • 接入的电压220v
  • 中间就需要继电器(适配口)
代码实现
class phone{
	constructor(){
		
	}
	fn(){
		return 22
	}
}
class Adaptive{
	constructor(){
		
	}
	fn(){
		return '220转为'+new Phone().fn()
	}
}
//实际使用的是对于的适配的内容
new Adaptive().fn()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值