JS设计模式——提高可扩展性(下)- 模块层面

目录

提高整体项目可扩展性的核心

提高可扩展性的设计模式

观察者模式

基本结构

 示例(多人合作问题、不同模块沟通,y型号的执行过程怎么办,转盘应用,下一圈减慢)

职责链模式

基本结构

 示例(axios的拦截器-不确定需求 、利用职责链组织一个表单验证)

访问者模式

基本结构

总结


提高整体项目可扩展性的核心

  • 低耦合
  • 良好的组织沟通方式

提高可扩展性的设计模式

架构-设计模块,并且组织模块沟通

观察者模式

目的:减少对象间的耦合,来提高扩展性

应用场景:当两个模块直接沟通会增加他们的耦合性时

// 无关组件互相传值 vuex eventbus
// a组件 -》  观察者 -》  b组件
// 事件绑定
// 执行   触发事件
// 设计模块
// 1.不好沟通-无关组件
// 2.异步模块     	观察者	同步模块

基本结构

// 定义一个中转观察者,两个模块之间不直接沟通,而是通过观察者。
// 一般适用于不方便直接沟通,或者异步操作
function observe(){
  this.message={};// 储存观察内容的对象
}
observe.prototype.regist=function(type,fn){ // 注册监听
   this.message[type]=fn;
}
observe.prototype.fire=function(type){ // 触发监听
   this.message[type]();
}
observe.prototype.remove=function(type){ // 删除监听
   this.message[type]=null;
}

 示例(多人合作问题、不同模块沟通,y型号的执行过程怎么办,转盘应用,下一圈减慢)

/ 多人合作问题(观察者模式)(无关组件沟通)
// 需求:现在假设A工程师写了首页模块,然后B工程师写了评论模块。现在要把评论展示在首页 
// a->首页
// b->评论
var observer = {// 不建议 ,变量权限,外部可直接调用 修改
    message: {
            
    },
    regist: {
            
    }
}
var observer = (function(){ // 推荐闭包
   var _message = {} // 监听内容
   return {
       fire: function (type, data) {// 触发监听
           _message[type](data);       
       },
       regist: function (type, fn) {// 注册监听
           return _message[type] = fn
       }   
   } 
})()
observer.regist('getComent', (data)=>{// 注册监听,data是收到的值
    // 处理data,评论展示在首页
})
var commont = observeOb.fire('getComent', data);// 触发监听,评论内容data传到监听
//观察者模式-不同模块沟通
function observeOb(){
  this.message={};// 储存观察内容的对象
}
observeOb.prototype.regist=function(type,fn){ // 注册监听
   this.message[type]=fn;
}
observeOb.prototype.fire=function(type){ // 触发监听
   this.message[type]();
}
function comment(){
  var self=this;
  this.commentList=[
    {
        type:'normal',
        content:'xxxxx'
    }
  ]
  observeOb.regist('indexComment',function(){
    var _arr=[];
    self.commentList.forEach((item)=>{
      if(item.type=='hot'){
          _arr.push(_item);
      }
    })
    return _arr; 
  })
}
function index(){
 observeOb.fire('indexComment');
}
// y型号的执行过程怎么办
// 请求接口1-a
// 请求接口2-b
// 做某事 a*b
function observe(){
  this.message={};// 储存观察内容的对象
}
observe.prototype.regist=function(type,fn){ // 注册监听
   this.message[type]=fn;
}
observe.prototype.fire=function(type,data){ // 触发监听
   this.message[type](data);
}
var arr = [];
observe.regist('finish', (data) => {
    arr.push(data);
    if (arr.length == 2) {
        run(arr);
    }
})

function mode1() {
    setTimeout(()=>{
       observe.fire('finish', 10)     
    }, Math.random() * 5000)// 1~5s
}
function mode2() {
    setTimeout(()=>{
         observe.fire('finish', 20)       
    }, Math.random() * 5000)// 1~5s
}
function run(arr) {
    console.log(arr[0] & arr[1])    
}
// 转盘应用,下一圈减慢
// 要做什么事
// 模块1:初始化转盘结构,
// 模块2:点击-》获取最终奖品,
// 模块3:转动控制模块(同步模块),
// 模块4:转动动画效果(异步模块,难通知控制模块)
// 300ms  转  10个奖品
// 观察者模式
var observer = (function(){ // 推荐闭包
   var _message = {} // 监听内容
   return {
       fire: function (type, data) {// 触发监听
           _message[type](data);       
       },
       regist: function (type, fn) {// 注册监听
           return _message[type] = fn
       }   
   } 
})()
// 1.初始化模块
var _domArr = []
function init(target) {
    // 创建10个奖品
    for(var i=0; i<=9; i++){
        var _div = document.createElement('div');
        _div.setAttribute("class","item");
        _div.innerHTML=i;
        target.appendChild(_div);
        _domArr.push(_div);
      }
}
// 1,2,3,4,5
// 2.获取最终奖品模块
function getFinal() { 
    var _num = Math.random() * 10 + 40; // 先转4圈,第五圈决定奖品
    return Math.floor(_num, 0);
}
// 3.转动控制模块
function moveControll() { 
    var _speed = 50;
    var final = getFinal();
    var _circle = Math.floor(final/10,0)
    var _runCircle = 0;//跑过的圈数
    var stopNum = final % 10;
    mover({
        speed: _speed,
        moveTime: 10    // 转动几个奖品
    })
    observer.regist('finish', () => {
        var _movetime = 0; // 跑的格
        _runCircle++;// 跑完一圈
        _speed += 50;// 速度加50
        if(_runCircle <= _circle) {
            _movetime = 10;        
        } else {
            _movetime = stopNum ;  
        }
        mover({
            moveTime: _movetime,
            speed: _speed
   	 });
    })
}
// 4.转动动画模块
function mover(moveConfig) { 
    var nowIn = 0;
    // 享元模式,提取不同点
    var removeNum = 9;
    var timer = setInterval(()=>{
        if (nowIn != 0) {
            removeNum = nowIn - 1;    
        }
        _domArr[removeNum].setAttribute("class", "item");
        _domArr[nowIn].setAttribute("class", "item item-on");
        nowIn++;
        if(nowIn == moveConfig.moveTime) {
            clearInterval(timer)   
            observer.fire('finish')// 通知一下,这圈转完了 
        }
    }, moveConfig.speed)
    
}
function observe(){
    this.message={};
}
observe.prototype.regist=function(type,fn){
    this.message[type]=fn;
}
observe.prototype.fire=function(type){
    this.message[type]();
}
var _domArr=[];
var observeOb=new observe();
function htmlInit(target){
  for(var i=0;i<=9;i++){
    var _div=document.createElement('div');
    _div.setAttribute("class","item");
    _div.innerHTML=i;
    target.appendChild(_div);
    _domArr.push(_div);
  }
}
function getFinal(){
  var _num=Math.random()*10+40;
  return Math.floor(_num,0);
}
function mover(moveConfig){
 var nowIn=0;
 var removeNum=9;
 
 var timer=setInterval(function(){
   if(nowIn!=0){
     removeNum=nowIn-1;
   } 
   _domArr[removeNum].setAttribute('class','item');
   _domArr[nowIn].setAttribute('class','item item-on');
   nowIn++;
   if(nowIn==moveConfig.moveTime){
     clearInterval(timer);
     if(moveConfig.moveTime==10){
        observeOb.fire('finish');
     }  
   }
 },moveConfig.speed);
}
function moveControll(){
 var final=getFinal();
 var _circle=Math.floor(final/10,0);
 var _runCircle=0;
 var stopNum=final%10;
 var _speed=200;
 mover({
    moveTime:10,
    speed:_speed
 });
 observeOb.regist('finish',function(){
    var _time=0;
    _speed-=50;
   _runCircle++;
   if(_runCircle<=_circle){
     _time=10;
   }else{
     _time=stopNum;
   }
 
   mover({
     moveTime:_time,
     speed:_speed
   });
 })
}
htmlInit(document.getElementById('app'));
moveControll();

职责链模式

a->b->c 组织成一个流水线

目的:为了避免请求发送者与多个请求处理者耦合在一起,形成一个链条

应用场景:把操作分割成一系列模块,每个模块只处理自己的事情

// 工厂-》水果加工工厂
// 每个工人都要负责整个水果加工环节((+消毒部门)要全培训)
// 洗水果  切水果 (+消毒部门)  水果加工   水果包装
// 就是你接收的这个需求,随时可能变动:职责链

基本结构

// l把要做的事情组织为一条有序的链条,通过这条链条传递消息来完成 功能。
// 适用于不涉及到复杂异步的操作
function mode1() {

}
function mode2() {

}
function mode3() {

}
_result = mode1(_result)
_result = mode2(_result)
_result = mode3(_result)

 示例(axios的拦截器-不确定需求 、利用职责链组织一个表单验证)

// axios的拦截器-不确定需求 	职责链模式
// 需求:axios拦截器的设计,大家可以看成一个用给职责链的思想去处理请求
axios.interceptors.request.use(()=>{
    // 成功回调
},()=>{
    // 失败回调
})
axios.interceptors.response.use(()=>{
    
})
function Axios(){
    this.interceptors = {
        request: new interceptorsManner(),  // 职责链是分开的
        response: new interceptorsManner(),  // 职责链是分开的  
    }
}
// 发请求
Axios.prototype.request = function() {
    // 职责链模式原则:每一个模块都是依次按顺序调用,并且传递消息
    var chain = [dispatchRequest, undefined];//(初始内容) 合并职责链-》最终职责链
    var promise = Promise.resolve();
    this.interceptors.request.handlers.forEach((interceptor)=>{
    	chain.unshift(interceptor.fullfilled, interceptor.rejected)// 请求拦截器(成功、失败一对)插入链条前面            
    })
    this.interceptors.response.handlers.forEach((interceptor)=>{
    	chain.push(interceptor.fullfilled, interceptor.rejected)// 响应拦截器插入链条后面            
    })
    while (){ //依次执行职责链中的每一环
    	// shift()执行数组最前面的,并且删除,但是会返回执行结果
        promise = promise.then(chain.shift(), chain.shift());   
    }
}

function interceptorsManner() {
 this.handlers=[]// 存放use加入的方法
}
interceptorsManner.protoType.use = function(fullfilled, rehected){
    this.handlers.push({
            fullfilled,
            rehected
    })
}
// koa中间件,职责链模式;链式调用可以看成是职责链模式,但是不准确,因为不能确定是否是模块
// 利用职责链组织一个表单验证
// 需求:有一个表单,需要先前台校验,在后端校验
input.onblur = function () {
    // 只需要验证一下是不是纯数组
    var _value = input.value;
    var _arr = [isNumber, back, other] // 职责链数组
    async function test() {
        var _result = _value;    
        while (_arr.length>0) {
            _result = await _arr.shift()(_result);        
        }
        return _result;
    }
    test().then((res)=>{
        // 判断res是否通过    
    })
}
function other() {
    
}

访问者模式

目的:解耦数据结构与数据的操作

应用场景:数据结构不希望与操作有关联

基本结构

// 通过定义一个访问者,代替直接访问对象, 来减少两个对象之间的耦合
 var data=[];
 var handler=function(){
      
 }
 handler.prototype.get=function(){
      
 }
 var vistor=function(handler,data){
   handler.get(data); 
 }
// 不同角色访问数据
// 需求:假设有一个公司的财务报表。财务关心支出和收入,老板关心盈利
function report(){
   this.income="";
   this.cost="";
   this.profit="";
 }
 
 function boss(){
 }
 boss.prototype.get=function(num){
    
 }
 function account(){
 }
 account.prototype.get=function(num1,num2){
 }
 function vistor(data,man){
   var handle={
     boss:function(data){
       man.get(data.profit);
     },
     account:function(data){
       account.get(data.income,data.cost);
     }
   }
   handle[man.constructor.name](data);
 }
 vistor(new report(),new boss());
// 表格操作
// 需求:一个可以新增,删除的表格
 function table(){
 }
 table.prototype.show=function(){
 }
 table.prototype.delete=function(id){
    vistor(this,tableData,'delete',id)
 }
 table.prototype.add=function(){
 }
 
  //访问者模式-表格
 var tableData=[
   {
     id:1,
     name:'xxx',
     price:'xxx'
   }
 ]
 function vistor(table,data,handle){
    var handleOb={
      delete:function(id){
        
      },
      add:function(){
        
      }
    };
    var arg=Array.prototype.splice(arguments);
    arg.splice(0,3);
    handleOb[handle].apply(this,arg);
 }

总结

观察者模式:适用于不适合直接沟通的模块之间的组织

职责链模式:组织同步模块,把要做的事情划分为模块,要做的事情依次传递

访问者模式:解耦数据操作与数据结构

如果发现有错误的地方或者任何建议,欢迎评论指正 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值