1: 第一种
// 单例模式(Singleton Pattern),后端用的比较多 // 单例模式创建多少对象就只有一个实例 var SinglePattern = (function(){ function Single(name) { this.name = name; } return function(name) { if(!Single.instance) { Single.instance = new Single(name) } return Single.instance } })() var obj1 = new SinglePattern("张三") var obj2 = new SinglePattern("李四")
2:第二种
var SinglePattern = (function(){ var instance = null; function Single(name) { this.name = name; } return function(name) { if(!instance) { instance = new Single(name) } return instance } })() var obj1 = new SinglePattern("张三") var obj2 = new SinglePattern("李四") console.log("obj1========",obj1); console.log("obj2========",obj2); console.log(obj1 === obj2);
应用场景:数据一致性
1: 第一种
function School(type) { var instance = new Object(); instance.name = type.name; instance.age = type.age; instance.gender = type.gender; return instance; } var student = School({name: '学生',age: 10,gender: '男'}) var teacher = School({name: '老师',age: 23,gender: '女'}) console.log("student",student); console.log("teacher",teacher);
2:第二种
// 历史 function History(d) { return this.data = d }; // 数学 function Math(d) { return this.data = d }; // 课程工厂 function FactoryPattern(type) { var Clazz = null; var data = null; switch(type) { case "history": Clazz = History; data = "历史" break; case "math": Clazz = Math; data = '数学'; break; } return new Clazz(data) } var c1 = FactoryPattern("history") var c2 = FactoryPattern("math") console.log(c1,c2);
工厂模式应用场景:工厂模式-创建(批量生产对象)
1: ES5写法
// 依赖收集器 function Dep() { this.subs = [] // 数据存储,存储需要订阅的内容,未来方便通知 } Dep.prototype.addSub = function(sub) { this.subs.push(sub) } // 事件触发方:通知的行为 Dep.prototype.notify = function() { this.subs.forEach(sub => { sub.update() }); } // 观察者模式 function Observer(name) { this.name = name; } Observer.prototype.update = function() { console.log(this.name,"检测到了更新"); } var obj1 = new Observer("小a") var obj2 = new Observer("小b") // 创建主题对象,对主题产生订阅 var dep = new Dep() dep.addSub(obj1) dep.addSub(obj2) dep.notify()
2: ES6写法
// 观察者模式 class Observer { constructor(name) { this.name = name; } update() { console.log(this.name + "更新了") } } // 依赖收集器 class Dep { constructor() { this.subs = [] } addSubs(watcher) { this.subs.push(watcher) } notify() { this.subs.forEach(w => { w.update() }) } } var obj1 = new Observer("小a") var obj2 = new Observer("小b") var dep = new Dep() dep.addSubs(obj1) dep.addSubs(obj2) dep.notify()
Observer 负责视图更新,Dep负责收集依赖和通知,视图和逻辑分离,具备消息订阅功能
应用场景: 消息订阅
class Bus { constructor(){ this.handlers = {} } // 实现事件订阅on on(name,callback) { // 没有就新增 if(!this.handlers[name]) { this.handlers[name] = [] } // 有的话就进行push this.handlers[name].push(callback) } // 实现事件发布emit emit(name,...args) { if(this.handlers[name]) { this.handlers[name].forEach(cb=>{ cb(...args) }) } } // 实现事件的销毁off off(name,callback) { const callbacks = this.handlers[name] const index = callbacks.indexOf(callback) if(index!=-1) { callbacks.splice(index,1) delete this.handlers[name] } console.log("this.handlers",this.handlers); } } var $bus = new Bus(); var fn1 = function(e) { console.log("e",e); } var fn2 = function(e) { console.log("e",e); } $bus.on("sendMessage",fn1) $bus.emit("sendMessage",{id:1,name:"张三"}) $bus.off("sendMessage",fn1) $bus.on("sendInfo",fn2) $bus.emit("sendInfo","你好呀!") $bus.off("sendInfo",fn2)
// Decorator Pattern 装饰器模式 function Coffee() { this.info = "苦咖啡"; } Coffee.prototype.show = function() { console.log(this.info); // 这个this就是构造函数本身 } // 装饰器 function CoffeeDecorator(coffee) { this.coffee = coffee; // 保存被装饰的对象 } // 加工外部操作,更加利于加工类的扩展和维护 CoffeeDecorator.prototype.show = function() { console.log("糖是甜的呦!"); this.coffee.show() } var co1 = new Coffee(); var coDc = new CoffeeDecorator(co1) coDc.show()
// 创建代理类 function Coffee() { this.info = "苦咖啡"; // 代码不利于维护 } Coffee.prototype.show = function() { console.log(this.info); } // 创建代理类 function CoffeeProxy() { // 用代理替换文本 不存在本体 this.coffee = new Coffee() } CoffeeProxy.prototype.show = function() { console.log("代理的甜"); this.coffee.show() } var cp1 = new CoffeeProxy() cp1.show()
其实装饰器模式和代理模式很相似,如何选择呢,根据当前是否有装饰着实例,如果没有,就用代理模式创建一个实例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <form action="" id="form"> <input type="text" id="username" placeholder="用户名" /><br /> <input type="text" id="password1" placeholder="密码" /><br /> <input type="text" id="password2" placeholder="确认密码" /><br /> <input type="text" id="phone" placeholder="电话" /><br /> <button>提交</button> </form> <script> function Validate() {} // 四个功能函数, 通过外部 调用rules[名称]获取 Validate.prototype.rules = { // 是否手机号 isMobile: function (str) { var rule = /^1[3,4,5,7,8,9][0-9]\d{8}$/; return rule.test(str); }, // 是否必填 isRequired: function (str) { // 除去首尾空格 var value = str.replace(/(^\s*)|(\s*$)/g, ""); return value !== ""; }, // 最小长度 minLength: function (str, length) { var strLength = str.length; return strLength >= length; }, // 是否相等 isEqual: function () { // 可以接收多个参数比较 var args = Array.prototype.slice.call(arguments); // 取首项与后面所有的项比较,如果每个都相等,就返回true var equal = args.every(function (value) { return value === args[0]; }); return equal; }, }; Validate.prototype.test = function (rules) { var v = this; var valid; // 保存校验结果 // 外部传递的规则配置参数rules for (var key in rules) { // 遍历校验规则对象 // 数组 for (var i = 0; i < rules[key].length; i++) { // 遍历每一个字段的校验规则 var ruleName = rules[key][i].rule; // 获取每一个校验规则的规则名 var value = rules[key][i].value; // 获取每一个校验规则的校验值 if (!Array.isArray(value)) { // 统一校验值为数组类型 value = new Array(value); } // ruleName // 确保this是validate对象 // [this.password2.value, 6] || this.password2.value var result = v.rules[ruleName].apply(v, value); // 调用校验规则方法进行校验 if (!result) { // 如果校验不通过,就获取校验结果信息,并立即跳出循环不再执行,节约消耗 valid = { errValue: key, errMsg: rules[key][i].message, }; break; } } if (valid) { // 如果有了校验结果,代表存在不通过的字段,则立即停止循环,节约消耗 break; } } return valid; // 把校验结果反悔出去 }; var formData = document.getElementById("form"); formData.onsubmit = function () { event.preventDefault(); var validator = new Validate(); // 验证规则 抽离出来, 便于更为灵活的应用验证器 // 【使用参数传递:便于扩展】 配置上更加语义化 // 将规则作为规则名称封装,【提高了复用性】 // 验证器已经和DOM解耦,只关心规则和数据以及message var result = validator.test({ // 和id一致才能获取 username: [ { rule: "isRequired", value: this.username.value, message: "用户名不能为空!", }, ], password1: [ { rule: "isRequired", value: this.password1.value, message: "密码不能为空!", }, { rule: "minLength", value: [this.password1.value, 6], message: "密码长度不能小于6个字符!", }, ], password2: [ { rule: "isRequired", value: this.password2.value, message: "确认密码不能为空!", }, { rule: "minLength", value: [this.password2.value, 6], message: "确认密码长度不能小于6个字符!", }, { rule: "isEqual", value: [this.password2.value, this.password1.value], message: "确认密码与原密码不相同!", }, ], isMobile: [ { rule: "isRequired", value: this.phone.value, message: "手机号不能为空!", }, { rule: "isMobile", value: this.phone.value, message: "手机号格式不正确!", }, ], }); if (result) { console.log(result); } else { console.log("校验通过"); } }; </script> </body> </html>
策略模式常用于代码的复用性和可扩展性
这个我们平常很常见
var xiaomi = { view() { console.log("显示小米屏幕"); } } var iphone = { view() { console.log("显示iphone屏幕"); } } // 保证手机的高内聚,所以我们吧后续的功能加到外边 // 调用手机,view的功能封装起来 function use(type) { if(type === 'xiaomi'){ xiaomi.view() } else if(type === 'iphone') { iphone.view() } } use("xiaomi")
适配器模式通常用于做代码的兼容