第2章 this call apply
bind()方法建立一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其他的参数将做为新函数的参数供调用时使用。
bind()方法底层实现javascript
Function.prototype.bind = Function.prototype.bind || function () { var self = this var rest1 = Array.prototype.slice.call(arguments) var context = rest1.shift() // 获取第一个参数,this的指向 return function () { var rest2 = Array.prototype.slice.call(arguments) // 获取其他参数 return self.apply(context, rest1.concat(rest2)) // 将预设参数和其他参数一块儿传参 } } var food = { name: '汉堡', price: '5块钱', getPrice: function (place,name) { console.log(place + this.price + name) } } var getPrice1 = food.getPrice.bind({ name: '鸡腿', price: '7块钱' }, '肯打鸡 ') getPrice1('jesse')
bind()的另外一个最简单的用法是使一个函数拥有预设的初始参数。只要将这些参数(若是有的话)做为bind()的参数写在this后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面html
第3章 闭包和高阶函数
高阶函数的应用
函数柯里化java
var curring = function(fn){ var args = []; return function(){ if(arguments.length === 0){ return fn.apply(this,args); }else{ [].push.apply(args,arguments); return arguments.callee; } } } var cost = (function(){ var money = 0; return function(){ for(var i = 0;,l = arguments.length;i < l;i++){ money += aruments[i]; } return money; } })() var cost = curring(cost); cost(100); console.log(cost());
uncurring()算法
Function.prototype.uncurring = fucntion(){ var self = this; return function(){ var obj = Array.prototype.shift.call(arguments); return self.apply(obj,arguments); } } var push = Array.prototype.push.uncurring(); (function(){ push(arguments,4); console.log(arguments); //[1,2,3,4] })(1,2,3);
函数节流,用于解决函数频繁被调用而形成的性能问题编程
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 firstTime = false; } if(timer){//500毫秒以内再次触发的缩放事件不处理 return false; } timer = setTimeout(function(){ clearTimeout(timer); timer = null; _self.apply(_me,args); },interval||500); }; }; window.onresize = throttle(function(){ console.log(1) },500);
惰性加载函数设计模式
var addEvent = function( elem, type, handler ){ if ( window.addEventListener ){ addEvent = function( elem, type, handler ){//重写函数,避免频繁调用嗅探函数 elem.addEventListener( type, handler, false ); } }else if ( window.attachEvent ){ addEvent = function( elem, type, handler ){ elem.attachEvent( 'on' + type, handler ); } } addEvent( elem, type, handler ); }; var div = document.getElementById( 'div1' ); addEvent( div, 'click', function(){ alert (1); }); addEvent( div, 'click', function(){ alert (2); });
第4章 单例模式
单例模式的核心是确保只有一个实例,并提供全局访问。
该模式可用于定义单一弹窗缓存
var CreateDiv = function( html ){ this.html = html; this.init(); }; CreateDiv.prototype.init = function(){ var div = document.createElement( 'div' ); div.innerHTML = this.html; document.body.appendChild( div ); }; //将建立对象和保证单一对象分开 var ProxySingletonCreateDiv = (function(){ var instance; return function( html ){ if ( !instance ){ instance = new CreateDiv( html ); } return instance; } })(); var a = new ProxySingletonCreateDiv( 'sven1' ); var b = new ProxySingletonCreateDiv( 'sven2' ); alert ( a === b );
ES6写法闭包
let instance class CreateDiv{ constructor(html){ if(instance){ return instance } this.html = html; this.init(); return instance = this } init(){ var div = document.createElement('div') div.innerHTML = this.html document.body.appendChild(div) } } var a = new CreateDiv( 'sven1' ); var b = new CreateDiv( 'sven2' ); console.log(a===b) // true
第5章 策略模式
策略模式指的是定义一系列的算法,把它们一个个封装起来,而且使它们能够相互替换
该模式经常使用于表单校验app
var strategies = { "S": function( salary ){ return salary * 4; }, "A": function( salary ){ return salary * 3; }, "B": function( salary ){ return salary * 2; } }; var calculateBonus = function( level, salary ){ return strategies[ level ]( salary ); }; console.log( calculateBonus( 'S', 20000 ) ); // 输出:80000 console.log( calculateBonus( 'A', 10000 ) ); // 输出:30000
5.6.2 用策略模式重构表单校验
/***********************策略对象**************************/ var strategies = { isNonEmpty: function( value, errorMsg ){ if ( value === '' ){ return errorMsg; } }, minLength: function( value, length, errorMsg ){ if ( value.length < length ){ return errorMsg; } }, isMobile: function( value, errorMsg ){ if ( !/(^1[3|5|8][0-9]{9}$)/.test( value ) ){ return errorMsg; } } }; /***********************Validator 类**************************/ var Validator = function(){ this.cache = []; }; Validator.prototype.add = function( dom, rules ){ var self = this; for ( var i = 0, rule; rule = rules[ i++ ]; ){ (function( rule ){ var strategyAry = rule.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 = function(){ for ( var i = 0, validatorFunc; validatorFunc = this.cache[ i++ ]; ){ var errorMsg = validatorFunc(); if ( errorMsg ){ return errorMsg; } } }; /***********************客户调用代码**************************/ var registerForm = document.getElementById( 'registerForm' ); var validataFunc = function(){ var validator = new Validator(); validator.add( registerForm.userName, [{ strategy: 'isNonEmpty', errorMsg: '用户名不能为空' }, { strategy: 'minLength:6', errorMsg: '用户名长度不能小于10 位' }]); validator.add( registerForm.password, [{ strategy: 'minLength:6', errorMsg: '密码长度不能小于6 位' }]); var errorMsg = validator.start(); return errorMsg; } registerForm.onsubmit = function(){ var errorMsg = validataFunc(); if ( errorMsg ){ alert ( errorMsg ); return false; } };
第6章 代理模式
虚拟代理在惰性加载中的应用
var miniConsole = (function(){ var cache = []; var handler = function( ev ){ if ( ev.keyCode === 113 ){ var script = document.createElement( 'script' ); script.onload = function(){ for ( var i = 0, fn; fn = cache[ i++ ]; ){ fn(); } }; script.src = 'miniConsole.js'; document.getElementsByTagName( 'head' )[0].appendChild( script ); document.body.removeEventListener( 'keydown', handler );// 只加载一次miniConsole.js } }; document.body.addEventListener( 'keydown', handler, false ); return { log: function(){ var args = arguments; cache.push( function(){ return miniConsole.log.apply( miniConsole, args ); }); } } })(); miniConsole.log( 11 ); // 开始打印log // miniConsole.js 代码 miniConsole = { log: function(){ // 真正代码略 console.log( Array.prototype.join.call( arguments ) ); }
缓存代理
var mult = function(){ console.log( '开始计算乘积' ); var a = 1; for ( var i = 0, l = arguments.length; i < l; i++ ){ a = a * arguments[i]; } return a; }; mult( 2, 3 ); // 输出:6 mult( 2, 3, 4 ); // 输出:24 //如今加入缓存代理函数: var proxyMult = (function(){ var cache = {}; return function(){ var args = Array.prototype.join.call( arguments, ',' ); if ( args in cache ){ return cache[ args ]; } return cache[ args ] = mult.apply( this, arguments ); } })(); proxyMult( 1, 2, 3, 4 ); // 输出:24 proxyMult( 1, 2, 3, 4 ); // 输出:24 咱们在经常在项目中遇到分页的需求,同一页的数据理论上只须要去后台拉取一次,这些已经拉取到的数据在某个地方被缓存以后,下次再请求同一页的时候,即可以直接使用以前的数据。
第7章 迭代器模式
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各类元素,而又不须要暴露该对象的内部表示框架
var getActiveUploadObj = function(){ //... }; var getFlashUploadObj = function(){ //... }; var getFormUploadObj = function(){ //... }; var iteratorUploadObj = function(){ for(var i=0,fn;fn=arguments[i++];){ var uploadObj = fn(); if(uploadObj !== false){ return uploadObj; } } }; var uploadObj = iteratorUploadObj(getActiveUploadObj,getFlashUploadObj,getFormUploadObj);
第8章 发布订阅模式
发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,全部依赖于它的对象都将获得通知。在 JavaScript 开发中,咱们通常用事件模型 来替代传统的发布—订阅模式。
var Event = (function(){ var clientList = {}, listen, trigger, remove; listen = function( key, fn ){ if ( !clientList[ key ] ){ clientList[ key ] = []; } clientList[ key ].push( fn ); }; trigger = function(){ var key = Array.prototype.shift.call( arguments ), fns = clientList[ key ]; if ( !fns || fns.length === 0 ){ return false; } for( var i = 0, fn; fn = fns[ i++ ]; ){ fn.apply( this, arguments ); } }; remove = function( key, fn ){ var fns = clientList[ key ]; if ( !fns ){ return false; } if ( !fn ){ fns && ( fns.length = 0 ); }else{ for ( var l = fns.length - 1; l >=0; l-- ){ var _fn = fns[ l ]; if ( _fn === fn ){ fns.splice( l, 1 ); } } } }; return { listen: listen, trigger: trigger, remove: remove } })(); Event.listen( 'squareMeter88', function( price ){ // 小红订阅消息 console.log( '价格= ' + price ); // 输出:'价格=2000000' }); Event.trigger( 'squareMeter88', 2000000 ); // 售楼处发布消息
第9章 命令模式
在面向对象设计中,命令模式的接收者被当成 command 对象的属性保存起来,同时约定执行命令的操做调用 command.execute 方法。在使用闭包的命令模式实现中,接收者被封闭在闭包产生的环境中,执行命令的操做能够更加简单,仅仅执行回调函数便可。不管接收者被保存为对象的属性,仍是被封闭在闭包产生的环境中,在未来执行命令的时候,接收者都能被顺利访问。用闭包实现的命令模式以下代码所示:
var RefreshMenuBarCommand = function( receiver ){ return { execute: function(){ receiver.refresh(); } } }; var setCommand = function( button, command ){ button.onclick = function(){ command.execute(); } }; var refreshMenuBarCommand = RefreshMenuBarCommand( MenuBar ); setCommand( button1, refreshMenuBarCommand );
第10章 组合模式
10.7 组合模式的例子——扫描文件夹
var Folder = function( name ){ this.name = name; this.files = []; }; Folder.prototype.add = function( file ){ this.files.push( file ); }; Folder.prototype.scan = function(){ console.log( '开始扫描文件夹: ' + this.name ); for ( var i = 0, file, files = this.files; file = files[ i++ ]; ){ file.scan(); } }; /******************************* File ******************************/ var File = function( name ){ this.name = name; }; File.prototype.add = function(){ throw new Error( '文件下面不能再添加文件' ); }; File.prototype.scan = function(){ console.log( '开始扫描文件: ' + this.name ); }; var folder = new Folder( '学习资料' ); var folder1 = new Folder( 'JavaScript' ); var folder2 = new Folder ( 'jQuery' ); var file1 = new File( 'JavaScript 设计模式与开发实践' ); var file2 = new File( '精通jQuery' ); var file3 = new File( '重构与模式' ) folder1.add( file1 ); folder2.add( file2 ); folder.add( folder1 ); folder.add( folder2 ); folder.add( file3 ); var folder3 = new Folder( 'Nodejs' ); var file4 = new File( '深刻浅出Node.js' ); folder3.add( file4 ); var file5 = new File( 'JavaScript 语言精髓与编程实践' ); folder.add( folder3 ); folder.add( file5 ); folder.scan();
10.8 一些值得注意的地方
- 组合模式不是父子关系 组合对象把请求委托给它所包含的全部叶对象,它们可以合做的关键是拥有相同的接口。
- 对叶对象操做的一致性
- 双向映射关系
第11章 模板方法模式
var Beverage = function(){}; Beverage.prototype.boilWater = function(){ console.log( '把水煮沸' ); }; Beverage.prototype.brew = function(){ throw new Error( '子类必须重写brew 方法' ); }; Beverage.prototype.pourInCup = function(){ throw new Error( '子类必须重写pourInCup 方法' ); }; Beverage.prototype.addCondiments = function(){ throw new Error( '子类必须重写addCondiments 方法' ); }; Beverage.prototype.customerWantsCondiments = function(){ return true; // 默认须要调料 }; Beverage.prototype.init = function(){//封装了子类的算法框架 this.boilWater(); this.brew(); this.pourInCup(); if ( this.customerWantsCondiments() ){ // 若是挂钩返回true,则须要调料 this.addCondiments(); } }; var CoffeeWithHook = function(){}; CoffeeWithHook.prototype = new Beverage(); CoffeeWithHook.prototype.brew = function(){ console.log( '用沸水冲泡咖啡' ); }; CoffeeWithHook.prototype.pourInCup = function(){ console.log( '把咖啡倒进杯子' ); }; CoffeeWithHook.prototype.addCondiments = function(){ console.log( '加糖和牛奶' ); }; CoffeeWithHook.prototype.customerWantsCondiments = function(){ return window.confirm( '请问须要调料吗?' ); }; var coffeeWithHook = new CoffeeWithHook(); coffeeWithHook.init();
模板方法模式是基于继承的一种设计模式,父类封装了子类的算法框架和方法的执行顺序, 子类继承父类以后,父类通知子类执行这些方法
第12章 享元模式
var Upload = function( uploadType){ this.uploadType = uploadType; }; Upload.prototype.delFile = function( id ){ uploadManager.setExternalState( id, this ); // (1) if ( this.fileSize < 3000 ){ return this.dom.parentNode.removeChild( this.dom ); } if ( window.confirm( '肯定要删除该文件吗? ' + this.fileName ) ){ return this.dom.parentNode.removeChild( this.dom ); } } var UploadFactory = (function(){ var createdFlyWeightObjs = {}; return { create: function( uploadType){ if ( createdFlyWeightObjs [ uploadType] ){ return createdFlyWeightObjs [ uploadType]; } return createdFlyWeightObjs [ 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 = '<span>文件名称:'+ fileName +', 文件大小: '+ fileSize +'</span>' + '<button class="delFile">删除</button>'; dom.querySelector( '.delFile' ).onclick = function(){ flyWeightObj.delFile( id ); } 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 }, { fileName: '2.html', fileSize: 3000 }, { fileName: '3.txt', fileSize: 5000 } ]); startUpload( 'flash', [ { fileName: '4.txt', fileSize: 1000 }, { fileName: '5.html', fileSize: 3000 }, { fileName: '6.txt', fileSize: 5000 } ]);
享元模式带来的好处很大程度上取决于如何使用以及什么时候使用,通常来讲,如下状况发生时 即可以使用享元模式。
- 一个程序中使用了大量的类似对象。
- 因为使用了大量对象,形成很大的内存开销。
- 对象的大多数状态均可以变为外部状态。
- 剥离出对象的外部状态以后,能够用相对较少的共享对象取代大量对象。
第13章 职责链模式
职责链模式的最大优势就是解耦了请求发送者和 N 个接收者之间的复杂关 系,因为不知道链中的哪一个节点能够处理你发出的请求,因此你只需把请求传递给第一个节点即 可
var order500 = function( orderType, pay, stock ){ if ( orderType === 1 && pay === true ){ console.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 = successor; }; Chain.prototype.passRequest = function(){ var ret = this.fn.apply( this, arguments ); if ( ret === 'nextSuccessor' ){ return this.successor && this.successor.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 ); chainOrder500.passRequest( 1, true, 500 ); // 输出:500 元定金预购,获得100 优惠券 chainOrder500.passRequest( 2, true, 500 ); // 输出:200 元定金预购,获得50 优惠券 chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券 chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足 Function.prototype.after = function( fn ){ var self = this; return function(){ var ret = self.apply( this, arguments ); if ( ret === 'nextSuccessor' ){ return fn.apply( this, arguments ); } return ret; } }; var order = order500yuan.after( order200yuan ).after( orderNormal ); order( 1, true, 500 ); // 输出:500 元定金预购,获得100 优惠券 order( 2, true, 500 ); // 输出:200 元定金预购,获得50 优惠券 order( 1, false, 500 ); // 输出:普通购买,无优惠券
第14章 中介者模式
中介者模式的做用就是解除对象与对象之间的紧耦合关系。增长一个中介者对象后,全部的相关对象都经过中介者对象来通讯,而不是互相引用,因此当一个对象发生改变时,只须要通知中介者对象便可。中介者使各对象之间耦合松散,并且能够独立地改变它们之间的交互。
var goods = { // 手机库存 "red|32G": 3, "red|16G": 0, "blue|32G": 1, "blue|16G": 6 } var colorSelect = document.getElementById( 'colorSelect' ), memorySelect = document.getElementById( 'memorySelect' ), numberInput = document.getElementById( 'numberInput' ), colorInfo = document.getElementById( 'colorInfo' ), memoryInfo = document.getElementById( 'memoryInfo' ), numberInfo = document.getElementById( 'numberInfo' ), nextBtn = document.getElementById( 'nextBtn' ); var mediator = (function(){ return { changed: function( obj ){ var color = colorSelect.value, // 颜色 memory = memorySelect.value,// 内存 number = numberInput.value, // 数量 stock = goods[ color + '|' + memory ];// 颜色和内存对应的手机库存数量 if ( obj === colorSelect ){ // 若是改变的是选择颜色下拉框 colorInfo.innerHTML = color; }else if ( obj === memorySelect ){ memoryInfo.innerHTML = memory; }else if ( obj === numberInput ){ numberInfo.innerHTML = number; } if ( !color ){ nextBtn.disabled = true; nextBtn.innerHTML = '请选择手机颜色'; return; } if ( !memory ){ nextBtn.disabled = true; nextBtn.innerHTML = '请选择内存大小'; return; } if ( ( ( number - 0 ) | 0 ) !== number - 0 ){ // 输入购买数量是否为正整数 nextBtn.disabled = true; nextBtn.innerHTML = '请输入正确的购买数量'; return; } nextBtn.disabled = false; nextBtn.innerHTML = '放入购物车'; } } })(); // 事件函数: colorSelect.onchange = function(){ mediator.changed( this ); }; memorySelect.onchange = function(){ mediator.changed( this ); }; numberInput.oninput = function(){ mediator.changed( this ); };
第15章 装饰者模式
由于装饰者对象和它所装饰的对象拥有一致的接口,因此它们对使用该对象的客户来讲是透 明的,被装饰的对象也并不须要了解它曾经被装饰过,这种透明性使得咱们能够递归地嵌套任意 多个装饰者对象
var plane = { fire: function(){ console.log( '发射普通子弹' ); } } var missileDecorator = function(){ console.log( '发射导弹' ); } var atomDecorator = function(){ console.log( '发射原子弹' ); } var fire1 = plane.fire; plane.fire = function(){ fire1(); missileDecorator(); } var fire2 = plane.fire; plane.fire = function(){ fire2(); atomDecorator(); } plane.fire(); // 分别输出: 发射普通子弹、发射导弹、发射原子弹
用AOP装饰函数
Function.prototype.before = function( beforefn ){ var __self = this; // 保存原函数的引用 return function(){ // 返回包含了原函数和新函数的"代理"函数 beforefn.apply( this, arguments ); // 执行新函数,且保证 this 不被劫持,新函数接受的参数 // 也会被原封不动地传入原函数,新函数在原函数以前执行 return __self.apply( this, arguments ); // 执行原函数并返回原函数的执行结果, 2 // 而且保证 this 不被劫持 } } Function.prototype.after = function( afterfn ){ var __self = this; return function(){ var ret = __self.apply( this, arguments ); afterfn.apply( this, arguments ); return ret; } }; document.getElementById = document.getElementById.before(function(){ alert (1); }); var button = document.getElementById( 'button' );
不喜欢这种污染原型的方式,那么咱们能够作一些变通
var before = function( fn, beforefn ){ return function(){ beforefn.apply( this, arguments ); return fn.apply( this, arguments ); } } var a = before( function(){alert (3)}, function(){alert (2)} ); a =before( a, function(){alert (1);} ); a();
第16章 状态模式
状态模式的关键是把事物的每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部
javascript版的状态机
var Light = function(){ this.currState = FSM.off; // 设置当前状态 this.button = null; }; Light.prototype.init = function(){ var button = document.createElement( 'button' ), self = this; button.innerHTML = '已关灯'; this.button = document.body.appendChild( button ); this.button.onclick = function(){ self.currState.buttonWasPressed.call( self ); // 把请求委托给FSM 状态机 } }; var FSM = { off: { buttonWasPressed: function(){ console.log( '关灯' ); this.button.innerHTML = '下一次按我是开灯'; this.currState = FSM.on; } }, on: { buttonWasPressed: function(){ console.log( '开灯' ); this.button.innerHTML = '下一次按我是关灯'; this.currState = FSM.off; } } }; var light = new Light(); light.init();
第17章 适配器模式
适配器模式的做用是解决两个软件实体间的接口不兼容的问题。使用适配器模式以后,本来因为接口不兼容而不能工做的两个软件实体能够一块儿工做。
var guangdongCity = { shenzhen: 11, guangzhou: 12, zhuhai: 13 }; var getGuangdongCity = function(){ var guangdongCity = [ { name: 'shenzhen', id: 11, }, { name: 'guangzhou', id: 12, } ]; return guangdongCity; }; var render = function( fn ){ console.log( '开始渲染广东省地图' ); document.write( JSON.stringify( fn() ) ); }; var addressAdapter = function( oldAddressfn ){ var address = {}, oldAddress = oldAddressfn(); for ( var i = 0, c; c = oldAddress[ i++ ]; ){ address[ c.name ] = c.id; } return function(){ return address; } }; render( addressAdapter( getGuangdongCity ) );
- 适配器模式主要用来解决两个已有接口之间不匹配的问题,它不考虑这些接口是怎样实现的,也不考虑它们未来可能会如何演化。适配器模式不须要改变已有的接口,就可以使它们协同做用。
- 装饰者模式和代理模式也不会改变原有对象的接口,但装饰者模式的做用是为了给对象增长功能。装饰者模式经常造成一条长的装饰链,而适配器模式一般只包装一次。代理模式是为了控制对对象的访问,一般也只包装一次。
- 外观模式的做用却是和适配器比较类似,有人把外观模式当作一组对象的适配器,但外观模式最显著的特色是定义了一个新的接口。
第18章 单一职责原则
SRP 原则体现为:一个对象(方法)只作一件事情
第19章 最少知识原则
最少知识原则要求咱们在设计程序时,应当尽可能减小对象之间的交互。若是两个对象之间没必要彼此直接通讯,那么这两个对象就不要发生直接的相互联系。常见的作法是引入一个第三者对象,来承担这些对象之间的通讯做用。若是一些对象须要向另外一些对象发起请求,能够经过第三 者对象来转发这些请求。
第20章 开放封闭原则
当须要改变一个程序的功能或者给这个程序增长新功能的时候,可使用增长代码的方式,可是不容许改动程序的源代码
经过封装变化的方式,能够把系统中稳定不变的部分和容易变化的部分隔离开来。在系统的 演变过程当中,咱们只须要替换那些容易变化的部分
第22章 代码重构
- 提炼函数
- 合并重复的条件判断
- 把条件分支语句提炼成函数
- 合理使用循环
- 提早让函数退出代替嵌套条件分支
- 传递对象参数代替过长的参数列表
- 尽可能减小参数数量
- 少用三目运算符
- 合理使用链式调用
- 分解大型类
- 用return退出多重循环