-
开闭原则: 对扩展开放,对修改关闭
-
里氏转换原则: 子类继承父类,单独完全可以运行
-
依赖倒转原则: 引用一个对象,如果这个对象有底层类型,直接引用底层类型
-
接口隔离原则: 每一个接口应该是一种角色
-
合成/聚合复用原则: 新的对象应使用一些已有的对象,使之成为新对象的一部分
- 迪米特原则: 一个对象应对其他对象有尽可能少的了解
单例模式
概念
var Singleton = (function () { var instantiated; function init() { /*这里定义单例代码*/ return { publicMethod: function () { console.log(‘hello world’); }, publicProperty: ‘test’ }; } return { getInstance: function () { if (!instantiated) { //确保只有一个实例 instantiated = init(); //使用init方法,是使publicMethod和publicProperty只在要使用的时候才初始化; } return instantiated; } };})();/*调用公有的方法来获取实例:*/Singleton.getInstance().publicMethod(); // hello world作用和注意事项
-
模块间通信
-
系统中某个类的对象只能存在一个
- 保护自己的属性和方法
-
注意this的使用
-
闭包容易造成内存泄露,不需要的要赶快清除
- 注意new的成本。(继承)
实例
var $ = function(id) { return typeof id === ‘string’ ? document.getElementById(id) : id;};
var Modal = function(id, html) { this.html = html; this.id = id; this.open = false;};
Modal.prototype.create = function() { if (!this.open) { var modal = document.createElement(‘div’); modal.innerHTML = this.html; modal.id = this.id; document.body.appendChild(modal); setTimeout(function() { modal.classList.add(‘show’); }, 0); this.open = true; }};
Modal.prototype.delete = function() { if (this.open) { var modal = $(this.id); modal.classList.add(‘hide’); setTimeout(function() { document.body.removeChild(modal); }, 200); this.open = false; }};
var createIntance = (function() { var instance; return function() { return instance || (instance = new Modal(‘modal’, ‘这是一个弹框’)) }})();
- 使用闭包封装了 instance 私有变量并返回一个函数
- 利用 || 语法判断如果 instance 不存在则执行后者的实例化 Modal 方法,存在则直接返回 instance,确保了只存在一个弹框实例
var operate = { setModal: null, open: function() { this.setModal = createIntance(); this.setModal.create(); }, delete: function() { this.setModal ? this.setModal.delete() : ”; }};
$(‘open’). = function() { operate.open();};$(‘delete’). = function() { operate.delete();};
构造函数模式
概念
作用和注意事项
-
用于创建特定类型的对象
-
第一次声明的时候给对象赋值
- 自己声明构造函数,赋予属性和方法
-
声明函数的时候处理业务逻辑
-
区分和单例的区别,配合单例实现初始化
-
构造函数大写字母开头
- 注意 new 的成本 (继承)
实例
function Person(name, age, job) { if (!(this instanceof Person)) { return new Person(name, age, job); } this.name = name; this.age = age; this.job = job; this.sayName = function() { return this.name + ‘is’ + this.age + ‘years old’; }}var person1 = new Person(“Davis”, 22, “student”);var person2 = Person(“Faker”, 21, “player”);console.log(person1.sayName()); // Davis is 22 years oldconsole.log(person2.sayName()); // Faker is 21 years old建造者模式
概念
作用和注意事项
-
分步创建一个复杂的对象
-
解耦封装过程和具体创建组件
- 无需关心组件如何组装
-
一定要一个稳定的算法进行支持(“分步骤”是一个稳定的算法)
- 加工工艺是暴露的
实例
//1.产出东西是房子//2.包工头调用工人进行开工而且他要很清楚工人们具体的某一个大项//3.工人是盖房子的 工人可以建厨房、卧室、建客厅//4.包工头只是一个接口而已 他不干活 他只对外说我能建房子function House() { this.kitchen = “”; this.bedroom = “”; this.livingroom = “”;}function Contractor() { this.construct = function(worker) { worker.construct_kitchen(); worker.construct_bedroom(); worker.construct_livingroom(); }}function Worker() { this.construct_kitchen =function() { console.log(“厨房建好了”); } this.construct_bedroom = function() { console.log(“卧室建好了”); } this.construct_livingroom = function() { console.log(“客厅建好了”); } this.submit = function() { var _house = new House(); _house.kitchen = “finished”; _house.bedroom = “finished”; _house.livingroom = “finished”; return _house; }};var worker = new Worker();var contractor = new Contractor();contractor.construct(worker);// 主人要房子var myhouse = worker.submit();console.log(myhouse);工厂模式
概念
作用和注意事项
-
对象构建十分复杂
-
需要依赖具体的环境创建不同的实例
- 处理大量具有相同属性的小对象
实例
var XMLHttpFactory = function() {};XMLHttpFactory.createXMLHttp = function() { var XMLHttp = null; // XMLHttpFactory.createXMLHttp()这个方法根据当前环境的具体情况返回一个XHR对象 if (window.XMLHttpRequest) { XMLHttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttp = new ActiveXObject(“Microsoft.XMLHTTP”) } return XMLHttp;};var AjaxHander = function() { var XMLHttp = XMLHttpFactory.createXMLHttp(); /*…具体操作… */}
var XMLHttpFactory = function() {};XMLHttpFactory.prototype = {// 如果真的要调用这个方法会抛出一个错误,它不能被实例化,只能用来派生子类 createFactory:function() { throw new Error(“This is an abstract class”); }}var XHRHandler = function() { XMLHttpFactory.call(this);};XHRHandler.prototype = new XMLHttpFactory();XHRHandler.prototype.constructor = XHRHandler; // 重新定义 createFactory 方法XHRHandler.prototype.createFactory = function() { var XMLHttp = null; if (window.XMLHttpRequest) { XMLHttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttp = new ActiveXObject(“Microsoft.XMLHTTP”) } return XMLHttp;}var AjaxHander = function() { var XMLHttp = XMLHttpFactory.createXMLHttp(); /*…具体操作… */}
代理模式
概念
作用和注意事项
-
远程代理(一个对象将不同空间的对象进行局部代理)
-
虚拟代理(根据需要创建开销很大的对象,如图片预加载)
-
安全代理(控制真实对象的访问权限)
- 智能指引(调用对象代理处理另外一些事情,如垃圾回收机制)
- 不能滥用代理,有时候仅仅是给代码增加复杂度
实例// 代理模式需要三方// 1.买家function buyer() { this.name = “Davis”;}// 2.中介function agent() {}agent.prototype.sell = function() { new seller(new buyer()).sell(“50万”)}// 3.卖家 收钱function seller(buyer) { this.buyer_name = buyer.name; this.sell = function(money) { console.log(“收到了来自” + this.buyer_name + money + “人民币”); // 收到了来自Davis50万人民币 }}(new agent).sell();
// 图片加载函数 var myImage = (function() { var imgNode = document.createElement(“img”); document.body.appendChild(imgNode); return { // 提供一个对外的setSrc接口,外界调用这个接口,可以给该img标签设置src属性 setSrc: function(src) { imgNode.src = src; } } })(); // 引入代理对象 var proxyImage = (function() { var img = new Image; img. = function() { // 图片加载完成,正式加载图片 myImage.setSrc(this.src); }; return { setSrc: function(src) { // 图片未被载入时,加载一张提示图片 myImage.setSrc(“file://c:/loading.png”); img.src = src; } } })(); // 调用代理对象加载图片 proxyImage.setSrc(“http://images/water.jpg”);命令模式
概念
-
发起者:发出调用命令即可,具体如何执行,谁执行并不需要清楚。
-
接受者:有对应的接口处理不同的命令,至于命令是什么,谁发出的,不用关心。
- 命令对象:上面讲发起者和接受者分开了,二者之间需要个连接桥梁。这就是命令对象。命令对象接受发送者的调用,然后调用接受者的相应接口。
作用和注意事项
-
将函数的封装、请求、调用结合为一体
-
调用具体的函数解耦命令对象与接收对象
- 提高程序模块化的灵活性
- 不需要借口一致,直接调用函数即可,以免造成浪费
实例
// 发送者var setCommond = function(button, fn) { button.onClick = function() { fn() }};// 执行命令者var menu = { reFresh: function() { console.log(“刷新”); }, add: function() { console.log(“增加”); }, delete: function() { console.log(“删除”); }};// 命令对象var commondObj = function(reciver) { return function() { reciver.reFresh(); }};var commondObj1 = commondObj(menu);setCommond(btn1, commondObj1);
策略模式
概念
-
发起者:发出调用命令即可,具体如何执行,谁执行并不需要清楚。
-
接受者:有对应的接口处理不同的命令,至于命令是什么,谁发出的,不用关心。
- 命令对象:上面讲发起者和接受者分开了,二者之间需要个连接桥梁。这就是命令对象。命令对象接受发送者的调用,然后调用接受者的相应接口。
作用
-
策略模式利用组合,委托等技术和思想,有效的避免很多if条件语句。
-
策略模式提供了开放-封闭原则,使代码更容易理解和扩展。
- 策略模式中的代码可以复用。
实例
/** * 针对不同情况的策略算法封装在策略类fucs中, * 从调用事件中去除繁琐的if或者switch逻辑判断。达到解耦的目的 * 加入后面再增加‘select’的选项增加对应的方法即可 */ var funcs = { text: function() { console.log(‘this is text’) }, radio: function() { console.log(‘this is radio’) }, checkbox: function() { console.log(‘this is checkbox’) }, default: function() { console.log(‘this is default’) } } var renderDom = function(type) { /** * 只需要根据不同的入参,自行匹配策略类中的接口即可。 */ return (funcs[type || funcs[‘default’])() }renderDom(‘checkbox’)
-
策略对象就是funcs对象,里面的不同属性接口对应的方法就是策略。与逻辑判断分离开,如果有不同的情况的出现,对应的增加属性接口即可。
-
renderDom方法就是对应的管理类,只需要根据不同的type,去调用funcs不同的方法就ok了。如果type没有对应的接口,那就调用默认的default对应接口。
- 调用事件,就保持不变。将tyoe类型传过去就好了。
职责链模式
概念
-
发送者知道链中的第一个接收者,它向这个接收者发送该请求。
-
每一个接收者都对请求进行分析,然后要么处理它,要么它往下传递。
-
每一个接收者知道其他的对象只有一个,即它在链中的下家(successor)。
- 如果没有任何接收者处理请求,那么请求会从链中离开。
实例
托运安排:
第一辆车: A:100 , B:250
第二辆车: A:0 , B:350
第三辆车: A:0 , B:350
第四辆车: A:0 , B:350
第五辆车: A:0 , B:100 ,C:250
第六辆车: A:0 , B:0 , C:250 ,D:100
class WearHouse{ constructor(volume,wearHouse){ this.volume=volume; this.wearHouse=wearHouse; this.outString=[]; } next(take){ if(this.wearHouse!=undefined) { this.wearHouse.takeOut(take).forEach((subT) => { this.outString.push(subT) }) } } takeOut(num){ if(num>this.volume){ num-=this.volume; var temp=this.volume; this.volume=0; this.outString.push(this.print(0,temp)); this.next(num); }else{ this.volume-=num; this.outString.push(this.print(this.volume,num)); } var temOut=this.outString; this.outString=[]; return temOut; } print(volumn,takeNum){} } class WearHouseA extends WearHouse{ print(volumn,takeNum){ return [‘A’,takeNum]; } } class WearHouseB extends WearHouse{ print(volumn,takeNum){ return [‘B’,takeNum]; } } class WearHouseC extends WearHouse{ print(volumn,takeNum){ return [‘C’,takeNum]; } } class WearHouseD extends WearHouse{ print(volumn,takeNum){ return [‘D’,takeNum]; } } var D=new WearHouseD(100,undefined); var C=new WearHouseC(500,D); var B=new WearHouseB(1400,C); var A=new WearHouseA(100,B); var strSet=[]; for(var a=0;a<6;a++){ strSet.push(…A.takeOut(350)); } console.log(strSet);结束语