设计模式


       设计模式的定义:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。
       GoF提出的23种软件设计模式,这里介绍几种常用的设计模式。

单例模式

在这里插入图片描述
       单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。
示例代码如下:

<script type="text/javascript">
		//单例模式
		Math.random()
		Math.random()
		console.log(Math==Math)
		class Dog{
			//统一接口
			static shareInstance(){
				if(!Dog.ins){
					Dog.ins = new Dog()
				}
				return Dog.ins;
			}
			constructor(){
			}
			wang(){
			}
		}
		let d1 = new Dog()
		let d2 = new Dog()
		console.log(d1==d2)
		let d3 = Dog.shareInstance()
		let d4 = Dog.shareInstance()
		let d5 = Dog.shareInstance()
		console.log(d3 === d4)
		console.log(d5 === d4)
</script>

       单例模式的适用场景:一个单一对象。比如:弹窗,无论点击多少次,弹窗只应该被创建一次,就像微信PC版。

组合模式

       组合模式的特点:
       1.组合模式在对象间形成树形结构;
       2.组合模式中基本对象和组合对象被一致对待;
       3.无须关心对象有多少层, 调用时只需在根部进行调用。
       想象我们现在手上有个万能遥控器, 当我们回家, 按一下开关, 下列事情将被执行:
       1.煮咖啡
       2.打开电视、打开音响
       3.打开空调、打开电脑
我们把任务划分为 3 类, 效果图如下:
在这里插入图片描述
示例代码如下:

<script type="text/javascript">
		const MacroCommand = function(){
			return {
				lists:[],
				add:function(task){
					this.lists.push(task)
				},
				excute:function(){//1.组合对象调用这里的excute,
					for(let i = 0;i < this.lists.length;i++){
						this.lists[i].excute()
					}
				},
			}
		}
		
		const command1 = MacroCommand() //命令1
		
		command1.add({
			excute:()=>console.log('煮咖啡')
		})
		
		const command2 = MacroCommand() //命令2
		
		command2.add({
			excute:()=>console.log('打开电视')
		})
		
		command2.add({
			excute:()=>console.log('打开音响')
		})
		
		const command3 = MacroCommand() //命令3
		
		command3.add({
			excute:()=>console.log('打开空调')
		})
		
		command3.add({
			excute:()=>console.log('打开电脑')
		})
		
		const macroCommand = MacroCommand()  //组合对象
		macroCommand.add(command1)
		macroCommand.add(command2)
		macroCommand.add(command3)
		
		macroCommand.excute()
</script>

       可以看出在组合模式中基本对象和组合对象被一致对待, 所以要保证基本对象(叶对象)和组合对象具有一致方法。

观察者模式

       核心思想:观察者只要订阅了被观察者的事件,那么当被观察者的状态改变时,被观察者会主动去通知观察者,而无需关心观察者得到事件后要去做什么,实际程序中可能是执行订阅者的回调函数。
       Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态,或者说执行对应对象的方法。
       这种设计模式可以大大降低程序模块之间的耦合度,便于更加灵活的扩展和维护。
       场景、当观察的数据对象发生变化时, 自动调用相应函数。比如 vue 的双向绑定。
示例代码如下:

<script type="text/javascript">
		var obj = {
			data:{
				list:[]
			},
		}
		
		//defineProperty可以观察obj对象的list属性的使用
		Object.defineProperty(obj,'list',{
			get(){
				console.log('获取了list属性')
				console.log(this.data['list'])
				return this.data['list']
			},
			set(val){
				console.log('值被更改了')
				this.data['list'] = val
			}
		})
		
		//获取了list属性,那么get方法就会被调用
		console.log(obj.list)
		//设置了list属性set方法就会被调用
		obj.list = ['a','b']
		console.log(obj.list)

</script>

工厂模式

       工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。js中构造函数就是工厂。
在这里插入图片描述
在这里插入图片描述
示例代码如下:

<script type="text/javascript">
		//文本工厂
		class Text{
			constructor(text) {
			    this.text = text;
			}
			insert(where){
				const txt = document.createTextNode(this.text);
				where.appendChild(txt);
			}
		}
		
		//链接工厂
		class Link{
			constructor(url) {
			    this.url = url;
			}
			insert(where){
				const link = document.createElement('a');
				link.href = this.url;
				link.appendChild(document.createTextNode(this.url));
				where.appendChild(link);
			}
		}
		let t = new Text('sd')
		t.insert(div)
		console.log(t)
// 			new Link('www.baidu.com')
</script>
抽象工厂模式

       抽象工厂模式:流程==》 先设计一个抽象类,这个类不能被实例化,只能用来派生子类,最后通过对子类的扩展实现工厂方法。
示例代码如下:

<script type="text/javascript">
		//DOM工厂
		class DomFactory{
			constructor() {
			    
			}
			//各流水线
			insert(){
				
			}
		}
		
		//链接工厂
		class Link2 extends DomFactory{
			constructor(url){
				this.url = url;
			}
			insert(where){
				const link = document.createElement('a');
				link.href = this.url;
				link.appendChild(document.createTextNode(this.url));
				where.appendChild(link);
			}
		}
</script>

策略模式

       策略模式的定义:定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。
       策略模式的目的就是将算法的使用算法的实现分离开来。
       一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类(可变),策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类Context(不变),Context接受客户的请求,随后将请求委托给某一个策略类。要做到这一点,说明Context中要维持对某个策略对象的引用。
示例代码如下:

<script type="text/javascript">
		//策略类
		var levelOBJ = {
			"A":function(money){
				return money * 4;
			},
			"B":function(money){
				return money * 3;
			},
			"C":function(money){
				return money * 2;
			}
		};
		//环境类
		var calculateBouns = function(level,money){
			return levelOBJ[level](money);
		};
		console.log(calculateBouns('A',10000))
		console.log(calculateBouns('B',10000))
		console.log(calculateBouns('C',10000))
</script>

代理模式

在这里插入图片描述
       js中的事件委托就是典型的代理模式。需要将自己的事情由中介去完成的就是代理模式。

示例代码如下:

<script type="text/javascript">
		const MyImage = function(parent){
			const imgNode = document.createElement('img')
			parent.appendChild(imgNode)
			
			//提供一个方法,让外部也能修改图片的src属性
			this.setSrc = function(src){
				imgNode.src = src;
			}
		}
		
		//直接添加图片,如果图片比较大,可能加载的比较慢,导致网页上的img一开始显示不出来
		let myImage = new MyImage(document.body)
		//写个代理 提供预加载功能
		const ProxyImage = function(myImage){
			//创建image对象
			const img = new Image()
			img.on
			//监听img对象的onload方法
			img.onload = function(){//http图片加载完毕后才会执行
			//模拟网络很慢的情况
			setTimeout(()=>{
				myImage.setSrc(this.src)
			},2000)
				
			}
			
			this.setSrc = function(src){
				//加载时候先不加载大图,先加载一张小图(浏览器已经下载过的)
				myImage.setSrc('loading.gif')//本地loading图片
				img.src = src
			}
		}
		//
		let proxyImage = new ProxyImage(myImage)
		proxyImage.setSrc('https://www.baidu.com/img/bd_logo1.png?where=super')
</script>

适配器模式

在这里插入图片描述
       适配器模式主要就是解决两个接口之间不匹配的问题,比如苹果电脑上没有网线插口,需要讲雷电借口或者USB借口转化为网线插口。
示例代码如下:

<script type="text/javascript">
		  // 老接口
    const zhejiangCityOld = function () {
        return [{
                name: 'hangzhou',
                id: 11,
            },
            {
                name: 'jinhua',
                id: 12
            }
        ]
    }

    console.log(zhejiangCityOld())

    // 新接口希望是下面形式
    // {
    //     hangzhou: 11,
    //     jinhua:12
    // }

    // 这时候就可采用适配者模式
    const adaptor = function (oldCity) {
        console.log(oldCity)
        const obj = {}
        for (let city of oldCity) {
            obj[city.name] = city.id
        }
        return obj
    }


    let oldData = zhejiangCityOld();
    //把老数据放在适配器中产生新数据
    console.log(adaptor(oldData))
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值