基本设计模式
Posted Vicky沛沛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基本设计模式相关的知识,希望对你有一定的参考价值。
gitbook完整版集合
文章目录
设计模式:针对特定的场景,在软件设计过程中常见的代码范式(通用解决方案,与语言无关)。
- 观察者模式(麦当劳点餐)
- 代理模式(花店送花)
- 装饰器:可以允许向一个对象添加新的功能,却不改变原有对象。比如:
- 给文件上传功能添加日志输出功能
- react中redux的
@connect
代理模式
- 特点:代理对象与真实对象有相同的行为
- 真实对象->代理对象->用户
- 花店送花:男孩让花店送花给女孩
//定义女孩对象
var Girl = function(name)
this.name = name;
var Boy = function(girl)
//女同学
this.girl = girl;
//送花
this.sendGift = function(gift)
console.log(this.girl.name+gift) //花店下订单,花店人去送花
//代理对象 花店员工
var ProxyObj = function(girl)
this.girl = girl; //需要知道女孩信息
this.sendGift = function(gift)
(new Boy(this.girl)).sendGift(gift) //替人送花;直接调用
//调用 不能看出是谁送花
var girl = new Girl('Vicky')
var proxy = new ProxyObj(girl)
proxy.sendGift("flowers")
- 代理模式的应用:图片懒加载
- 真实图片:大、加载慢;代理图片:小,加载快
//常用图片懒加载
window.onload = function()
var myImage = (function() //自执行函数
var imgNode = document.createElement('img') //创建真实图片节点
document.body.appendChild(imgNode) //图片节点加到body
var img = new Image() //代理对象 先展示代理图片 接着拉取实际图片
img.onload = function() //真实图片加载完毕后触发
imgNode.src = this.src; //把真实图片url给真实图片节点;替换等待图片;this指向代理对象
return //返回一个对象
setSrc:function(src)
imgNode.src = 'https://th.bing.com/th/id/R20d0cd9f696181bbead3b250782239fc?rik=SozVXnglW3zBxg&riu=http%3a%2f%2fbpic.588ku.com%2felement_pic%2f01%2f35%2f08%2f79573bd17084b13.jpg&ehk=UPH3Ji9JG4ZMqBzH9qKIJwuFG2R31XoHzvp4NkK5vXc%3d&risl=&pid=ImgRaw'; //代理图片url给到真实对象;先展示等待图片
img.src = src; //把src给到代理对象
)()
//调用:把真实图片给到对象
myImage.setSrc("https://himg.bdimg.com/sys/portrait/item/pp.1.d64a7775.reheWDHF3vrjPLK3n-YgKw.jpg?tt=1623053822499"); //真实图片
使用代理模式重构图片懒加载
window.onload = function()
var myImage = (function()
var imgNode = document.createElement('img')
document.body.appendChild(imgNode)
return
setSrc:function(src)
imgNode.src = src;
)()
//代理对象:先展示等待图片,再拉取真实图片
var ProxyImage = (function()
var img = new Image() //内存中的代理
img.onload = function() //加载完之后将触发这个方法
myImage.setSrc(this.src) //this指向img;将真实图片给真实对象展示
return
setSrc:function(src)
myImage.setSrc('https://th.bing.com/th/id/R20d0cd9f696181bbead3b250782239fc?rik=SozVXnglW3zBxg&riu=http%3a%2f%2fbpic.588ku.com%2felement_pic%2f01%2f35%2f08%2f79573bd17084b13.jpg&ehk=UPH3Ji9JG4ZMqBzH9qKIJwuFG2R31XoHzvp4NkK5vXc%3d&risl=&pid=ImgRaw') //代理图片
img.src = src;
)()
//调用;直接给代理对象设置真实图片 ProxyImage.setSrc('https://himg.bdimg.com/sys/portrait/item/pp.1.d64a7775.reheWDHF3vrjPLK3n-YgKw.jpg?tt=1623053822499') //真实图片
观察者模式(发布订阅模式)
场景:双十一购买商品。购买者:观察者;商品:被观察者;商家(商品价格修改):发布者。发布者发布,关注着会收到改变。
观察者、被观察者、发布者
//观察者
var shopObj =
//商品列表 ['huawei':['订阅人1','订阅人2'],'apple':['订阅人3','订阅人2'],'oppo':['订阅人1']]
shopObj.list = []
//订阅;根据特定的商品推给特定人
shopObj.listen = function(goodskey,fn) //商品订阅方法;fn订阅的行为; 建立商品和观察者的联系
if(!this.list[goodskey])
this.list[goodskey] = []
shopObj.list[goodskey].push(fn) //往特定商品列表中添加订阅
shopObj.publish = function()
var goodskey = arguments[0]
var fns = this.list[goodskey]
for(var i = 0,fn;fn = fns[i++];)
//执行订阅的fn
fn.apply(this,arguments)
//用户1:添加订阅
shopObj.listen('huawei',function(brand,model)
console.log('user 1'+brand,model)
)
//用户2:添加订阅
shopObj.listen('apple',function(brand,model)
console.log('user 2'+brand,model)
)
//商家发布订阅
shopObj.publish('huawei','P40')
观察者模式优化
//订阅发布放一起;之后再初始化
var event =
list:[],
listen:function(key,fn)
if(!this.list[key])
this.list[skey] = []
shopObj.list[key].push(fn) //往特定商品列表中添加订阅
,
publish:function()
var goodskey = arguments[0]
var fns = this.list[goodskey]
for(var i = 0,fn;fn = fns[i++];)
//执行订阅的fn
fn.apply(this,arguments)
//观察者对象初始化
var initEvent = function(obj)
for(var i in event)
obj[i] = event[i];
//定义空发布者
var shopObj = //空对象
initEvent(shopObj) //将我们定义的方法属性都给它
//用户1:添加订阅
shopObj.listen('huawei',function(brand,model)
console.log('user 1'+brand,model)
)
//用户2:添加订阅
shopObj.listen('apple',function(brand,model)
console.log('user 2'+brand,model)
)
//商家发布订阅
shopObj.publish('huawei','P40')
装饰器
-
给对象添加额外行为但是没有改变原有对象
-
简单装饰器的实现
class Circle
draw()
console.log('draw a circle')
//使用装饰器添加一个边框
class Decorator
constructor(circle)
this.circle = circle;
draw()
this.circle.draw() //圆自己绘制
this.setBorder() //增加绘制方法
setBorder(circle) //装饰器方法
console.log('draw border')
var circle = new Circle()
var dec = new Decorator(circle)
dec.draw()
- 装饰器–注解形式
class Boy
@run
speak()
console.log('speak')
function run(target,key,descriptor) //装饰器参数。
//target是Boy对象;key是被装饰的方法speak;descriptor是描述方法(writeable可写;enumerable可枚举,即是否可以for循环出来;configuerable可配置)
console.log('run')
var boy = new Boy()
boy.speak()
需要配置babel
,使用transform-decoarors-legacy
将@
转化成ES5代码;安装之后使用babel xxx.js -o /build/xxx.js
进行转化。
cnpm i -S babel-cli babel-preset-env babel-plugin-transform-decoarors-legacy
//babel-preset-env用于ES6转ES5
//babel-plugin-transform-decoarors-legacy用于注解翻译的
- 装饰器参数
- target 对象
- key被装饰的方法
- descriptor 描述对象
//给方法添加日志输出功能;不改变原有功能,添加新功能
class Math
@log
add(a,b)
return a+b;
//日志装饰器
function log(target,name,descriptor)
var oldValue = descriptor.value; //descriptor.value是被修饰的方法,add
descriptor.value = function()
console.log(`调用$name`参数是`$arguments`) //arguments是js的内置对象,包含所有实参的类数组
return oldValue.apply(target,arguments)
return descriptor;
var math = new Math();
math.value(1,3)
装饰器添加参数
//给方法添加日志输出功能,并且带上参数,加到a、b上;
class Math
@log(100)
add(a,b)
return a+b;
//日志装饰器
function log(num)
return function log(target,name,descriptor)
var _num = num || 0;
var oldValue = descriptor.value;
descriptor.value = function(...args)
arg[0] += _num; //改变原有参数值
arg[1] += _num;
console.log(`调用$name`参数是`$args`)
return oldValue.apply(target,args)
return descriptor;
var math = new Math();
math.value(1,3)
职责链模式
- 场景:充值抽奖
开闭原则:原有代码对现有需求时关闭的,对扩展时开放的
充值500抽100rmb;充值200抽20rmb;否则无奖
function(orderType,isPay,count) //订单类型;是否支付成功;金额
if(orderType === 1) //500rmb
if(isPay)
console.log('中奖100rmb')
else
if(count>0)
console.log('抽到纪念奖')
else
console.log('谢谢参与')
else if(orderType === 2) //200rmb
if(isPay)
console.log('中奖20rmb')
else
if(count>0)
console.log('抽到纪念奖')
else
console.log('谢谢参与')
else if(orderType === 3)
console.log('谢谢参与')
- 使用职责链模式重构
function order500(orderType,isPay,count)
if(orderType === 1 && isPay) //500rmb
if(isPay)
console.log('中奖100rmb')
else
//console.log('不关我的事,给下一个处理')
order200(orderType,isPay,count)
function order200(orderType,isPay,count)
if(orderType === 2 && isPay) //500rmb
if(isPay)
console.log('中奖100rmb')
else
//console.log('不关我的事,给下一个处理')
orderdefault(orderType,isPay,count)
function orderdefault(orderType,isPay,count)
if(count>0 && isPay)
console.log('抽到纪念奖')
else
console.log('谢谢参与')
- 使用职责链再次重构
function order500(orderType,isPay,count)
if(orderType === 1 && isPay) //500rmb
if(isPay)
console.log('中奖100rmb')
else
//console.log('不关我的事,给下一个处理')
return "nextSuccessor"
function order200(orderType,isPay,count)
if(orderType === 2 && isPay) //500rmb
if(isPay)
console.log('中奖100rmb')
else
//console.log('不关我的事,给下一个处理')
return "nextSuccessor"
function orderdefault(orderType,isPay,count)
if(count>0 && isPay)
console.log('抽到纪念奖')
else
console.log('谢谢参与')
//创建职责链关系对象
function Chain(fn)
this.fn = fn;
this.successor = null;
//设置下一个关系对象
Chain.prototype.setnextSuccessor =function(successor)
this.successor = successor;
//传递给下一个
Chain.prototype.passRequest = function()
var ret = this.fn.apply(this,arguments)
if(ret === 'nextSuccessor') //传给下一个
this.successor && this.successor.passRequest.apply(this.successor,arguments)
//实例化
var chain500 = new Chain(order500)
var chain200 = new Chain(order200)
var chaindefault = new Chain(orderdefault)
chain500.setnextSuccessor = chain200;
chain200.setnextSuccessor = chaindefault;
//调用
chain500.passRequest(1,true,100) //类型1 支付成功 金额500
面向对象:抽象、多态、继承、封装
以上是关于基本设计模式的主要内容,如果未能解决你的问题,请参考以下文章
html网页制作期末大作业-网上花店html+css+javascript
HTML5期末大作业:鲜花主题网页设计——简约的网上花店网站设计(4页) HTML+CSS+JavaScript