基本设计模式

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

基本设计模式

基本设计模式

基于javaweb网上花店系统的设计与实现.rar(项目源码+论文设计)

基本设计模式