设想形式运用举例

纸上得来终觉浅,进修设想形式,看了许多书,然则一直照样以为不如直接看例子来的越发客观详细,下面重要记录了js中的几个罕见的设想形式举例,供本身今后温习的时刻可以直接经由过程例子更快更好的明白设想形式。

单例形式

保证一个类唯一一个实例,并供应一个全局接见进口

var getSingleton = function(fn){
    var result;
    
    return function(){
        return result || (result = fn.apply(this, arguments));
    }
}

var createLoginLayer = function(){
    var div;
    
    return function(){
        if(!div){
            div = document.createElement('div');
            div.innerText = '这是弹窗';
            div.style.display = 'none';
            document.body.appendChild(div);
        }
        
        return div;
    }
});

var singletonCreateLoginLayer = getSingleton(createLoginLayer);

document.getElementById('loginBtn').onclick = function(){
    var layer = singletonCreateLoginLayer();
    layer.style.display = 'block';
}

战略形式

定义一系列算法,并使之可以互相替换。目标就是使算法的运用和定义分离出来。

var Strategy = {
    S: function(salary){
        return salary * 4;
    },
    A: function(salary){
        return salary * 3;
    },
    B: function(salary){
        return salary * 2;
    }
};

var getBouns = function(strategy, salary){
    return Strategy[strategy](salary);
}

getBouns('B', 1000); // 2000

表单校验

var strategies = {
    isNonEmpty: function(value, errorMsg){
        ....
    },
    minLength: function(value, length, errorMsg){
        ....
    },
    isMobile: function(value, errorMsg){
        ...
    }
};

var Validator = function(){
    this.cache = [];
};

Validator.prototype.add = function(dom, rule, errorMsg){
    var ary = [rule];
    
    this.cache.push(function(){
        var strategy = ary.shift();
        ary.unshift(dom.value);
        ary.push(errorMsg);
        return strategies[strategy].apply(dom, ary);
    });
}

Validator.prototype.start = function(){
    for(var i=0, validatorFunc; validatorFunc = this.cache[i++]){
        var msg = validatorFunc();
        if(msg){
            return msg;
        }
    }
}

var validatorFunc = function(){
    var validator = new Validator(); // 建立一个对象
    
    validator.add(...);
    
    var errorMsg = validator.start(); // 猎取校验效果
}

var registerForm = document.getElementById('form');
registerForm.onsubmit = function(){
    var errorMsg = validatorFunc();
    
    if(errorMsg){
        return false;
    }
}

代办形式

为一个对象供应一个代用品或占位符,以便掌握对它的接见。当客户不方便直接接见一个对象或许不满足须要的时刻供应一个替身对象来掌握对这个对象的接见,客户实际上接见的是替身对象。

单一职责准绳指的是,就一个类(平常也包含对象和函数等)而言,应当唯一一个引发它变 化的缘由。假如一个对象 了多 职责,就意味着这个对象将变得 大,引发它变化的缘由可 能会有多个。面向对象设想 将行动分 到细 度的对象当中,假如一个对象 的职责过量, 即是把这些职责耦合到了一同,这类耦合会 致 和低内聚的设想。当变化发作时,设想可以 会 到不测的 。

假造代办

图片懒加载

const myImg = (
  const node = documnet.createElement('img')
  document.body.appendChild(node)
  return {
    setSrc(src) {
       node.src= src
    }
  }
)()

const proxy = (
  const img = new Image()
  img.onload = () => {
    myImg.setSrc(this.src)
  }
  return {
    setImg(src) {
      img.src = src
      myImg.setSrc('loading.gif')
    }
  }
)()

观察者形式

宣布定阅形式又叫观察者形式,它定义对象间的一种一对多的依靠关联,当一个对象的状况发作转变时,一切依靠于它的对象都将获得关照。在JavaScript开辟中,我们平常用事宜模子来替换传统的宣布定阅形式。

const Event = (
  function() {
    var eventList = {}
    var addEventListen
    var trigger
    var remove 
    addEventListen = function(eventName, fn) {
      eventList[eventName] = eventList[eventName] || []
      eventList[eventName].push(fn)
    }
    trigger = function() {
      var key = Array.prototype.shift.call(arguments)
      var fns = eventList[key]
      if (!fns || !fns.length) {
         return
      }
      fns.forEach((fn, index) => {
        fn.apply(this, arguments)
      })
    }
    remove = function(eventName, fn) {
      var fns = eventList[eventName]
      if (!fns || !fns.length) {
       return false
      }
      if (!fn) {
        fns.length = 0
      } else {
        fns.forEach((_fn, index) => {
          if(fn === _fn) {
            fns.splice(index, 1)
          } 
        })
      }
    }
    return {
      addEventListen,
      trigger,
      remove
    }
  }
)()

var testFn = () => {
    console.log('you have click a cancel btn')
}

Event.addEventListen('click', () => {
  console.log('you have click a button')
})

Event.addEventListen('click', () => {
  console.log('you have click button2')
})

Event.addEventListen('click', () => {
  console.log('you have click button3')
})

Event.addEventListen('click', testFn)

Event.remove('click', testFn)
Event.trigger('click')

享元形式

享元形式是为机能优化而生的,在一个存在大批类似对象的体系中,享元形式可以很好地处理大批对象带来的机能题目

文件上传

// uploadType作为内部状况,再抽离外部状况
var Upload = function(uploadType){
    this.uploadType = uploadType;
};

// 定义删除文件的要领
Upload.prototype.delFile = function(id){
    uploadManager.setExternalState(id, this); // 设置外部状况
    
    if(this.fileSize < 3000){
        return this.dom.parentNode.removeChild(this.dom);
    }
    
    if(window.confirm('确定要删除文件吗?'+ file.fileName)){
        return this.dom.parentNode.removeChild(this.dom);
    }
};

// 工场举行对象实例化
var UploadFactory = (function(){
    var createFlyWeightObjs = {};
    return {
        create: function(uploadType){
            if(createFlyWeightObjs[uploadType]){
                return createFlyWeightObjs[uploadType];
            }
            
            return createFlyWeightObjs[uploadType] = new Upload(uploadType);
        }
    }
})();

// 管理器封装外部状况
var uploadManager = (function(){
    var uploadDataBase = {}; // 存储外部状况
    
    return {
        add: function(id, uploadType, fileName, fileSize){
            var flyWeightObj = UploadFactory.create(uploadType);
            
            var dom = document.createElement('div');
            dom.innerHTML = '...';
            document.body.appendChild(dom);
            
            uploadDataBase[id] = { // 增添外部状况
                fileName: fileName,
                fileSize: fileSize,
                dom: dom
            };
            
            return flyWeightObj;
        },
        setExternalState: function(id, flyWeightObj){ // 设置外部状况
            var uploadData = uploadDataBase[id];
            for(var i in uploadData){
                flyWeightObj[i] = uploadData[i];
            }
        }
    }
})();

var id = 0;

window.startUpload = function(uploadType, files){
    for(var i = 0, file; file = files[i++];){
        var uploadObj = uploadManager.add(++id, uploadType, file.fileName, file.fileSize);
    }
};

startUpload('plugin', [
    {
        fileName: '1.txt',
        fileSize: 1000
    },
    ...
]);

对象池

对象池保护一个装载余暇对象的池子,假如须要对象的时刻,不是直接new,而是转从对象池里猎取。假如对象池没有余暇对象,则建立一个新的对象,当猎掏出的对象完成它的职责以后,再进入池子守候被下次猎取。

var objectPoolFactory = function(createObjFn){
    var objectPool = [];
    
    return {
        create: function(){
            var obj = objectPool.length === 0 ?
                createObjFn.apply(this, arguments) : objectPool.shift();
            
            return obj;
        },
        recover: function(obj){
            objectPool.push(obj);
        }
    };
};

// 如今应用`ObjectPoolFactory`来建立一个装载一些`iframe`的对象池
var iframeFactory = objectPoolFactory(function(){
    var iframe = document.createElement('iframe');
    document.body.appendChild(iframe);
    
    iframe.onload = function(){
        iframe.onload = null;
        iframeFactory.recover(iframe);
    }
    
    return iframe;
});

var iframe1 = iframeFactory.create();
iframe1.src = 'http://baidu.com';

var iframe2 = iframeFactory.create();
iframe2.src = 'http://qq.com';

setTimeout(function(){
    var iframe3 = iframeFactory.create();
    iframe3.src = 'http://163.com';
}, 3000);

中介者形式

用一个中介者对象来封装一系列的对象交互。中介者使各个对象之间不会互相援用。从而使其到达松懈耦合的目标。
与观察者形式对照来看,中介者形式是观察者形式中的同享被观察者对象。在这个体系中的对象之间直接的宣布/定阅关联被捐躯掉了,取而代之的是保护一个通讯的中间节点。

写顺序是为了疾速完成项目托付临盆,而不是堆砌形式和过渡设想。症结就在于怎样去权衡对象之间的耦合水平。假如对象之间的庞杂耦合确切致使挪用和保护涌现了难题,而且这些耦合度随项目标变化呈指数增进曲线,那就可以斟酌用中介者形式来重构代码。

function Player(name, teamColor){
    this.name = name; // 角色名字
    this.teamColor = teamColor; // 部队色彩
    this.state = 'alive'; // 玩家生计状况
}

Player.prototype.win = function(){ 
    console.log('winner:' + this.name);
};

Player.prototype.lose = function(){ 
    console.log('loser:' + this.name);
};

Player.prototype.die = function(){
    this.state = 'dead';
    playerDirector.ReceiveMessage('playerDead', this); // 给中介者发送音讯,玩家殒命
};

Player.prototype.remove = function(){
    playerDirector.ReceiveMessage('removePlayer', this);  // 给中介者发送音讯,移除一个玩家
};

Player.prototype.changeTeam = function(){
    playerDirector.ReceiveMessage('changeTeam', this); // 给中介者发送音讯,玩家换队
};

var playerFactory = function(name, teamColor){
    var newPlayer = new Player(name, teamColor);
    playerDirector.ReceiveMessage('addPlayer', newPlayer); // 给中介者发送音讯,新增玩家
    
    return newPlayer;
};

// 完成playerDirector对象
var playDirector = (function(){
    var players = {}; // 保留一切玩家
    var operations = {}; // 中介者可以实行的操纵
    
    // 新增一个玩家
    operations.add = function(player){
        var teamColor = player.teamColor;
        players[teamColor] = players[teamColor] || [];
        players[teamColor].push(player);
    };
    
    // 移除一个玩家
    operations.removePlayer = function(player){
        var teamColor = player.teamColor;
        var teamPlayers = players[teamColor] || [];
        
        for(var i=teamPlayers.length - 1; i >= 0 ;i --){
            if(teamPlayers[i] === player){
                teamPlayers.splice(i, 1);
            }
        }
    };
    
    // 玩家换队
    operations.changeTeam = function(player, newTeamColor){
        operations.removePlayer(player); // 从原部队中删除
        player.teamColor = newTeamColor; // 换色彩
        operations.addPlayer(player); // 新增玩家到新的部队
    }
    
    operations.playerDead = function(player){
        var teamColor = player.teamColor;
        var teamPlayer = players[teamColor];
        
        var all_dead = true;
        
        // 遍历队友列表
        for(var i=0, player; player = teamPlayer[i++];){
            if(player.state !== 'dead'){
                all_dead = false;
                break;
            }
        }
        
        // 假如队友悉数殒命
        if(all_dead === true){
            this.lose();
            
            // 关照一切队友玩家游戏失利
            for(var i=0, player; player = teamPlayer[i++];){
                player.lose();
            }
            
            // 关照一切仇人游戏成功
            for(var color in players){
                if(color !== teamColor){
                    var teamPlayers = players[color];
                    for(var i=0, player; player = teamPlayers[i++];){
                        player.win();
                    }
                }
            }
        }
    }
    
    var ReceiveMessage = function(){
        var message = Array.prototype.shift.call(arguments);
        operations[message].apply(this, arguments);
    };
    
    return {
        ReciveMessage: ReceiveMessage
    }
})();

// 建立8个玩家对象
var player1 = playerFactory('a', 'red');
var player2 = playerFactory('b', 'red');
var player3 = playerFactory('c', 'red');
var player4 = playerFactory('d', 'red');

var player5 = playerFactory('e', 'blue');
var player6 = playerFactory('f', 'blue');
var player7 = playerFactory('g', 'blue');
var player8 = playerFactory('h', 'blue');

装潢者形式

给对象动态地增添职责的体式格局称为装潢者形式。
装潢者形式可以在不转变对象本身的基础上,在顺序运转时期给对象动态地增添职责。跟继续比拟,装潢者是一种更轻巧天真的做法,这是一种“即用即付”的体式格局。
函数经由过程Function.prototype.before或许Function.prototype.after被装潢以后,返回的实际上是一个新的函数,假如在原函数上保留了一些属性,那末这些属性会丧失。
这类装潢体式格局也叠加了函数的作用域,假如装潢的链条太长,机能上也会遭到一些影响。

Function.prototype.before = function(beforeFn){
    var _self = this; 
    return function(){ 
        if(beforefn.apply(this, arguments) === false){
            return;
        }; 
        return _self.apply(this, arguments); 
    }
};

var validata = function(){
    if(username.value === ''){
        alert('不能为空');
        return false;
    }
    
    if(password.value === ''){
        alert('不能为空');
        return false;
    }
};


var formSubmit = function(){
    var param = {
        username: username.value,
        password: password.value
    };
    
    ajax('....');
};

formSubmit = formSubimt.before(validata);

submitBtn.onclick = function(){
    formSubmit();
};

状况形式

状况形式的症结是把事物的每种状况都封装成零丁的类,跟此种状况有关的行动都被封装在这个类的内部,只须要在上下文中,把某个要求托付给当前的状况对象即可,该状况对象会福州衬着它本身的行动。

// Light 类
var Light = function(){
    this.offLightState = new OffLightState(this);
    this.weekLightState = new WeekLightState(this);
    this.strongLightState = new StrongLightState(this);
    this.button = null;
};

Light.prototype.init = function(){
    var button = document.createElement('button');
    var self = this;
    
    this.button = document.body.appendChild(button);
    this.button.innerHTML = '开关';
    
    this.currState = this.offLightState;
    
    this.button.onclick = function(){
        self.currState.buttonWasPressed();
    };
};
// offLightState
var OffLightState = function(light){
    this.light = light;
};

OffLightState.prototype.buttonWasPressed = function(){
    console.log('弱光') // offLightState 对应的行动
    this.light.setState(this.light.weekLightState); // 切换状况到 weekLightState
};

文中代码重要来自曾探先生的《JavaScript设想形式与开辟实践》,书中的内容关于设想形式写的越发详确仔细,假如想进修设想形式引荐这本书入门哈!

    原文作者:wupengyu
    原文地址: https://segmentfault.com/a/1190000017278544
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞