在做canvas、webGL游戏时,很深切的感觉到,游戏编程玩的都是设计模式。架构没预先设计好,强耦合性代码在后期维护简直灾难。
大型单页应用里,复杂度上升到一定程度时,没有适当的设计模式进行降耦,后续的开发也难以下手。
而设计模式正是为了降耦而存在。
参考《javascript设计模式》——曾探
函数节流
var throttle = function(fn, interval){
var _self = fn,
timer,
firstTime = true;
return function(){
var args = arguments.
_me = this;
if( firstTime ){
_self.apply(_me, args);
return first
}
if(timer){
return false;
}
timer = setTimeout(function(){
clearTimeout(timer);
timer = null;
_self.apply(_me, args);
}, interval || 500);
}
}
window.onresize = throttle(function(){
console.log(1);
}, 500);
分式函数
var timeChunk = function(arr, fn, count){
var obj, t;
var len = ary.length;
var start = function(){
for(var i = 0; i < Math.min(coutn||1, arr.length); i++){
var obj = ary.shift();
fn(obj);
}
}
return function(){
t = setInterval(function(){
if(ary.length === 0){
return clearInterval(t);
}
start();
}, 200);
};
};
惰性函数(重写自重写)
var addEvent = function(elem, type, handler){
if(window.addEventListener){
addEvent = function(elem, type, handler){
elem.addEventListener(type, handler, false);
}
} else if(window.addachEvent){
addEvent = function(elem, type, handler){
elem.attachEvent('on' + type, handler);
}
}
}
单例模式
定义:保证类有且仅有一个实力,并提供全局访问接口。
私有变量加下划线 var _a = 1;
通用惰性单例模式
把创建单例和管理单例的职责分开来:
var getSingle = function(fn){
var result;
return function(){
return result || (result = fn.apply(this, arguments));
}
}
var createLayer = function(){
var div = document.createElement('div');
document.body.appendChild(div);
}
var createSingleCreateLayer = getSingle(createLayer);
document.getElementById('#test').onclick = () => {
createSingleCreateLayer();
}
策略模式
定义:封装一系列算法,并使其可以相互替换
计算工资Demo:
var strategies = {
'S': function(salary){
return salary * 4;
},
'A': function(salary){
return salary * 3;
}
}
var calculateBonus = (level, salary) => {
return strategies[level](salary);
}
表单添加多种校验规则:
/*--------------- Strategies --------------*/
var strategies = {
isNotEmpth: (value, errorMsg) => {
if(value == ''){
return errorMsg;
}
},
minLength: (value, length,errorMsg) => {
if(value.length < length){
return errorMsg;
}
}
}
/*---------------- Validator ---------------*/
var Validator = () => {
this.cache = [];
}
Validator.prototype.add = (dom, rules) => {
var self = this;
for(var i = 0; rule; rule = rules[i++]){
((rule) => {
var strategyAry = strategy.split(':');
var errorMsg = rule.errorMsg;
self.cache.push(function(){
var strategy = strategyAry.shift();
strategyAry.unshift(dom.value);
strategyAry.push(errorMsg);
return strategies[strategy].apply(dom, strategyAry);
});
})(rule);
}
};
Validator.prototype.start = () => {
for(var i = 0; validatorFunc; validatorFunc = this.cache[i++]){
var errorMsg = validatorFunc();
if( errorMsg ){
return errorMsg;
}
}
}
/*-------------- 客户端调用 ------------*/
var registerForm = document.getElementById('registerForm');
var validataFunc = () => {
var validator = new Validator();
validator.add(registorForm.username, [{
strategy: 'isNotEmpty',
errorMsg: '用户名不能为空'
},{
strategy: 'minLength',
errorMsg: ‘最下长度为6’
}]);
validator.add(registorForm.password, [{
strategy: 'minLength',
errorMsg: '最小长度'
}])
var errorMsg = validator.start();
return errorMsg;
}
registerForm.onsubmit = () => {
var errorMsg = validataFunc();
if(errorMsg){
alert(errorMsg);
return false;
}
}
代理模式
为一个对象提供一个代用品或者占位符,以便控制它的访问
面向对象设计原则——单一职责原则。面向对象设计鼓励将行为分布到细粒度的对象之中。
大量计算时加入代理作为缓存,异步请求时同理可用缓存:
var mult = () => {
var a = 1;
for(var i = 0, l = arguments.length; i < l; i++){
a = a * arguments[i];
}
return a;
}
var proxyMult = (() => {
var cache = {};
return () => {
var args = Array.prototype.join.call(arguments, ',');
if( args in cache ){
return cache[args];
}
return cache[args] = mult.apply(this, arguments);
}
})();
高阶函数动态创建代理
var mult = () => {
var a = 1;
for(var i = 0, l = arguments.length; i < l; i++){
a = a * arguments[i];
}
return a;
}
var plus = () => {
var a = 0;
for(var i = 0, l = arguments.length; i < l; i++){
a = a + arguments[i];
}
return a;
}
var createProxyFactory = (fn) => {
var cache = {};
return () => {
var args = Array.prototype.join.call(arguments, ',');
if(args in cache){
return cache[args];
}
return cache[args] = fn.apply(this, arguments);
}
}
迭代器模式
迭代器模式指提供一种方法顺序访问一个聚合对象的各个元素,又不暴露该对象的内部表示。
通用外部迭代器:
var Iterator = (obj) => {
var current = 0;
var next = () => {
++current;
}
var isDone = () => {
return current >= obj.length;
}
var getCurrItem = () => {
return obj[current];
}
return {
next: next,
isDone: isDone,
getCurrItem: getCurrItem
}
}
发布-订阅模式
var event = {
clientListh: [],
listen: function(key, fn){
if(!this.clientListh[key]){
this.clientList[key] = [];
}
this.clientList[key].push(fn);
},
trigger: function(){
var key = Array.prototype.shift.call(arguments),
fns = this.clientList[key];
if(!fns || fns.length === 0){
return false;
}
for(var i = 0; fn; fn = fns[i++]){
fn.apply(this.arguments);
}
}
}
var installEvent = function(obj){
for(var i in event){
obj[i] = event[i];
}
};
var salesOffices = {};
installEvnet(salesOffices);
salesOffices.listen('squareMeter88', function(price){
console.log('price': + price);
})
salesOfffices.trigger('squareMeter88', 20000);
发布——订阅模式可以很大程度降低耦合性,但滥用也会造成背后逻辑混乱,且浪费内存。
命令模式
主要是回调函数的的面向对象的替代品
没看懂命令模式有什么意义
撤销和重做
var commandStack = [];
document.onkeypress = (ev)=>{
var keyCode = ev.keyCode,
command = makeCommand(Ryu, commands[keyCode]);
if(command){
command();
commandStack.push(command);
}
}
$('#replay').onclick = ()=>{
var command;
while(command = commandStack.shift()){
command();
}
}
宏命令
var closeDoorCommand = {
excute: ()=> {
console.lg('close door');
}
}
var openPcCommand = {
excute: ()=> {
console.log('open pc');
}
}
var MacroCommand = ()=> {
return {
conmandList: [],
add: (command)=>{
this.commandList.push(command);
},
execute: ()=>{
for(var i = 0, command; command = this.commandsList[i++]; ){
command.execute();
}
}
}
}
组合模式
类似命令模式的加强版,也是看不懂深层意义
遍历文件夹
/************ Folder ****************/
var Folder = (name)=>{
this.name = name;
this.parent = null;
this.files = [];
};
Folder.prototype.add = (file)=> {
file.parent = this;
this.files.push(file);
}
Folder.prototype.scan = ()=>{
console.log('Begin scan: ' + this.name);
for(var i = 0, file = this.files; file = files[i++]; ){
file.scan();
}
}
Folder.prototype.remove = ()=>{
if(!this.parent){
return;
}
for(var files = this.parent.files, l = files.length-1; l >= 0; l--){
var file = files[l];
if(file === this){
files.splice(l, 1);
}
}
}
/************ File ****************/
var File = (name)=>{
this.name = name;
this.parent = null;
}
File.prototype.add = ()=>{
throw new Error('Can not add file under file');
}
File.prototype.scan = ()=>{
console.log('Begin Scan: ' + this.name);
}
File.prototype.remove = ()=>{
if(!this.parent){
return;
}
for(var files = this.parent.files, l = files.length-1; l >= 0; l--){
var file = files[l];
if(file == this);{
file.splice(l, 1);
}
}
}
模板方法模式
基于继承的设计模式
模板方法模式友抽象父类和具体实现的子类组成。父类封装了子类的算法框架,子类通过集成抽象类,也继承了整个算法框架。
钩子方法
var Bevrage = function(){}
Beverage.prototype.boilWater = function(){
console.log('把水煮沸');
}
Beverage.prototype.brew = function(){
throw new Error('Class brew musth be rewrited');
}
....
Beverage.prototype.addCondiments = function(){
throw new Error('adCondiments must be rewrited');
}
Beverage.prototype.customerWantsCondiments = function(){
return true;
}
Beverage.prototype.init = function(){
this.boilWater();
this.brew();
....
if(this.customerWantsCondiments()){
this.addCondiments();
}
}
var CoffeeWithHook = function(){};
CoffeeWithHook.prototype = new Beverage();
CoffeeWithHook.prototype.brew = function(){
console.log('brew coffee with water');
};
CoffeeWithHook.prototype.customerWantsCondiments = function(){
return widow.confirm('需要调料嘛?');
}
var coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.init();
高阶函数可以更方便的实现上面的demo...
享元模式
用于性能优化,核心是运用共享技术来支持大量细粒度的对象。
通用对象池的实现
var objectPoolFactory = (createObjFn)=>{
var objectPool = [];
return{
create: function(){
var obj = objectPool.length === 0 ? createObjFn.apply(this, arguments) : objectPool.shift();
return obj;
},
recover: (obj){
objectPool.push(obj);
}
}
}
职责链模式
用来重构代码挺方便的。
把不同功能函数包装成链式节点再调用。
var order500 = function(orderType, pay, stock){
if(orderType == 1 && pay == true){
conosle.log('500, 100优惠券')
} else{
return 'nextSuccessor'; // 把请求往后传递
}
}
var order200 = function(orderTYPE, pay, stock){
if(orderType == 2 && pay ==true){
console.log('200, 50优惠券');
} else{
return 'nextSuccessor';
}
}
var orderNormal = function(orderType, pay, stock){
if(stock > 0){
console.log('普通购买,无优惠券');
} else{
console.log('库存不足');
}
}
//职责链包装函数
//Chain.prototype.setNextSuccessor 指定在链中的下一个结点
//Chain.prototype.passRequest 请求传递给某个结点
var Chain = function(fn){
this.fn = fn;
this.successor = null;
}
Chain.prototype.setNextSuccessor = function(successor){
return this.successor = seccussor;
}
Chain.prototype.passRequest = function(){
var ret = this.fn.apply(this, arguments);
if(ret === 'nextSuccessor'){
return this.successor && this.seccessor.passRequest.apply(this.successor, arguments);
}
return ret;
}
//将订单函数包装进职责链
var chainOrder500 = new Chain(order500);
var chainOrder200 = new Chain(order200);
var chainOrderNormal = new Chain(orderNormal);
chainOrder500.setNextSuccessor(chainOrder200);
ChainOrder200.setNextSuccessor(chainOrderNormal);
//Test]
chainOrder500.pasRequest(1, true, 500);
中介者模式
个人感觉有点像代理模式.用一个中介对象,来处理其他对象的时间,以实现解耦的目的。
但缺点也很明显,当系统复杂到一定程度时,中介者对象慢慢会变成一个难以维护的对象
装饰者模式
动态的给类添加职责