建议使用以下浏览器,以获得最佳体验。 IE 9.0+以上版本 Chrome 31+ 谷歌浏览器 Firefox 30+ 火狐浏览器
请选择 进入手机版 | 继续访问电脑版
设置昵称

在此一键设置昵称,即可参与社区互动!

确定
我再想想
选择版块
直达楼层
标签
您还可以添加5个标签
  • 没有搜索到和“关键字”相关的标签
  • 云产品
  • 解决方案
  • 技术领域
  • 通用技术
  • 平台功能
取消

采纳成功

您已采纳当前回复为最佳回复

前端小盆友

发帖: 15粉丝: 1

发消息 + 关注

更新于2021年03月26日 09:26:44 600 2
直达本楼层的链接
楼主
显示全部楼层
[技术干货] 常用设计模式

### 设计与模式 之前一直以为「设计模式」是一个完整的名词 其实「设计」和「模式」是要分开来说的 **「设计」:5 个常见的设计原则** **「模式」:代码中常见的"套路",被程序员总结成了相对固定的写法,称之为「模式」** 也就是说学习"设计模式",首先肯定要学习和理解 5 个设计原则。 #### 五大设计原则-SOLID - S(single)-单一职责原则- 一个程序只做好一件事;如果功能过于复杂就拆分开,每个部分保持独立; - O(open-close)-开放封闭原则- 对扩展开放,对修改封闭;增加需求时,扩展新代码,而非修改已有代码; - L(Liskov)-里氏置换原则-子类能覆盖父类;父类能出现的地方子类就能出现; - I(Interface)-接口独立原则-保持接口的单一独立,避免出现”胖接口“;js中没有接口(typescript除外),使用少; - D(Dependence)-依赖倒置原则-编程依赖抽象接口,不要依赖具体实现;使用方只关注接口而不关注具体类的实现; **示例 promise** - 单一职责原则:每个 then 中的逻辑制作好一件事 - 开放封闭原则:如果新增需求,扩展 then ```js // 0.0.1/loadImg.js function loadImg(src) { let promise = new Promise(function (resolve, reject) { let img = document.createElement('img'); img.onload = function () { resolve(img); } img.onerror = function () { reject('图片加载失败'); } img.src = src; }); return promise; } let imgUrl = 'https://raw.githubusercontent.com/ruizhengyun/images/master/cover/ruizhengyun.cn_.png'; loadImg(imgUrl).then(function (img) { console.log(`width: ${img.width}`); return img; }).then(function (img) { console.log(`height: ${img.height}`); }).catch(function (ex) { console.log(ex); }); ``` #### Javascript 常用设计模式 -- 工厂模式 工厂模式也称创建模式,是用于创建对象的一种方式。可以说就是用来代替 new 实例化对象,决定了实例化哪一个类,从而解决解耦问题。 **拟物化解读** 一个工厂接到一笔订单(传参),然后根据这个订单类型(参数)来安排产品线(实例化哪个类),当然客户可以要求一些产品的工艺属性(抽象工厂)。这其中厂长(工厂模式)只负责调度,即安排产品零件流水线。你应该知道的是,工厂有个特点就是产出体量大、相似度高的产品。如果你要做单一定制化的产品,那这笔订单给工厂就不适用了。 **其作用(利)** 解耦,通过使用工程方法而不是 new 关键字; 将所有实例化的代码集中在一个位置减少代码重复,降低出错; **具体实现** 分步创建一个复杂的对象,解耦封装过程和具体创建组件(分解为零件流水线); 无需关心组件如何组装(厂长在调度); 不暴露创建对象的具体逻辑,将逻辑封装在一个函数中(客户只需要告诉工厂做什么和提一些要求); **适用场景** 处理大量具有相同属性的小对象; 对象的构建十分复杂,需要依赖具体环境创建不同实例 **分类(抽象程度)** 不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂。 ##### 简单工厂模式 也可以叫静态工厂模式,用一个工厂对象创建同一类对象类的实例。现实生活中,用户在平台还是分等级的,角色不同,权限也不同。 **1.ES5 实现** ```js // 0.0.2/es5.simple.factory.js function Role(options){ this.role = options.role; this.permissions = options.permissions; } Role.prototype.show = function (){ var str = '是一个' + this.role + ', 权限:' + this.permissions.join(', '); console.log(str) } function simpleFactory(role){ switch(role) { case 'admin': return new Role({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); break; case 'developer': return new Role({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); break; default: throw new Error('参数只能为 admin 或 developer'); } } // 实例 const xm = simpleFactory('admin'); xm.show(); const xh = simpleFactory('developer'); xh.show(); const xl = simpleFactory('guest'); xl.show(); ``` **2.ES6 实现** ```js // 0.0.2/simple.factory.js class SimpleFactory { constructor(opt) { this.role = opt.role; this.permissions = opt.permissions; } // 静态方法 static create(role) { switch (role) { case 'admin': return new SimpleFactory({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); break; case 'developer': return new SimpleFactory({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); break; default: throw new Error('参数只能为 admin 或 developer'); } } show() { const str = `是一个${this.role}, 权限:${this.permissions.join(', ')}`; console.log(str); } } // 实例 const xm = SampleFactory.create('admin'); xm.show(); const xh = SampleFactory.create('developer'); xh.show(); const xl = SampleFactory.create('guest'); xl.show(); ``` 或 ```js // 0.0.2/simple.factory2.js class Role { constructor(options) { this.role = options.role; this.permissions = options.permissions; } show() { const str = `是一个${this.role}, 权限:${this.permissions.join(', ')}`; console.log(str); } } class SimpleFactory { constructor(role) { if(typeof this[role] !== 'function') { throw new Error('参数只能为 admin 或 developer'); } return this[role](); } admin() { return new Role({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); } developer() { return new Role({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); } } // 实例 const xm = new SimpleFactory('admin'); xm.show(); const xh = new SimpleFactory('developer'); xh.show(); const xl = new SimpleFactory('guest'); xl.show(); ``` 上例中,simpleFactory 就是一个简单工厂,2个实例对应不同的权限,调用工厂函数时,只需传递 admin 或 developer 就可获取对应的实例对象。 **1.简单工厂函数适用场景** 正确传参,就可以获取所需要的对象,无需知道内部实现细节; 内部逻辑(工厂函数)通过传入参数判断实例化是使用哪些类; 创建对象数量少(稳定),对象的创建逻辑不复杂; **2.简单工厂函数不适用场景** 当需要添加新的类时,就需要修改工厂方法,这违背了开放封闭原则(OCP, 对扩展开放、对源码修改封闭)。函数 create 内包含了所有创建对象(构造函数)的判断逻辑代码,如果要增加新的构造函数还需要修改函数 create(判断逻辑代码),当可选参数 role 变得更多时,那函数 create 的判断逻辑代码就变得臃肿起来,难以维护。 不适用创建多类对象; ##### 工厂方法模式 将实际创建对象工作推迟到子类当中,核心类就成了抽象类。这样添加新的类时就无需修改工厂方法,只需要将子类注册进工厂方法的原型对象中即可。 **1.ES5 实现**,ES5 没有像传统创建类的方式那样创建抽象类,所以工厂方法模式只需参考其核心思想即可。可将工厂方法看做一个实例化对象工厂类(采用安全模式类),将创建对象的基类放在工厂方法类的原型中即可。当需要添加新类时,只需挂载在 FunctionFactory.prototype 上,无需修改工厂方法,也实现了 OCP 原则。 ```js // 0.0.2/es5.function.factory.js function FunctionFactory(role) { if(!(['admin', 'developer'].indexOf(role) > -1)){ throw new Error('参数只能为 admin 或 developer'); } // 安全的工厂方法 if (this instanceof FunctionFactory) { return this[role](); } return new FunctionFactory(role); } FunctionFactory.prototype.show = function () { var str = '是一个' + this.role + ', 权限:' + this.permissions.join(', '); console.log(str) } FunctionFactory.prototype.admin = function (permissions) { this.role = '管理员'; this.permissions = ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论']; } FunctionFactory.prototype.developer = function (permissions) { this.role = '开发者'; this.permissions = ['开发', '推送', '提问', '评论']; } var xm = FunctionFactory('admin'); xm.show(); var xh = new FunctionFactory('developer'); xh.show(); var xl = new FunctionFactory('guest'); xl.show(); ``` **2.ES6 实现**,由于 ES6 中还没有 abstract,就用 new.target 来模拟出抽象类(new.target 指向被 new 执行的构造函数),判断 new.target 是否指向了抽象类,如果是就报错。 ```js // 0.0.2/function.factory.js class FunctionFactoryBase { // 抽象类 constructor(role) { if (new.target === FunctionFactoryBase) { throw new Error('抽象类不能实例'); } this.role = role; } } class FunctionFactory extends FunctionFactoryBase { // 子类 constructor(role) { super(role); } static create(role) { switch (role) { case 'admin': return new FunctionFactory({ role: '管理员', permissions: ['设置', '删除', '新增', '创建', '开发', '推送', '提问', '评论'] }); break; case 'developer': return new FunctionFactory({ role: '开发者', permissions: ['开发', '推送', '提问', '评论'] }); break; default: throw new Error('参数只能为 admin 或 developer'); } } show() { const { role, permissions } = this.role; const str = `是一个${role}, 权限:${permissions.join(', ')}`; console.log(str) } } // let xl = new FunctionFactoryBase(); // 此行会报错,注释后方可正常执行后面 let xm = FunctionFactory.create('admin'); xm.show() let xh = FunctionFactory.create('developer'); xh.show() let xl = FunctionFactory.create('guest'); xl.show() ``` ##### 抽象工厂模式 抽象工厂只留对外的口子,不做事,留给外界覆盖(子类重写接口方法以便创建的时候指定自己的对象类型)。主要用于对产品类簇的创建,不直接生成实例(简单工厂模式和工厂方法模式都是生成实例)。 - 抽象类是一种声明但不能使用的类,子类必须先实现其方法才能调用; - 可以在抽象类中定义一套规范,供子类去继承实现; ```js // 0.0.2/abstract.factory2.js // 抽象工厂 function AbstractFactory(subType, superType) { if (typeof AbstractFactory[superType] === 'function') { //缓存类 function F() { } //继承父类属性和方法 F.prototype = new AbstractFactory[superType](); //将子类 constructor 指向子类(自己) subType.prototype.constructor = subType; //子类原型继承缓存类(父类) subType.prototype = new F(); } else { //不存在该抽象类抛出错误 throw new Error('抽象类不存在') } } // 抽象类 AbstractFactory.Phone = function () { this.type = 'Phone'; } AbstractFactory.Phone.prototype = { showType: function () { return new Error('Phone 抽象方法 showType 不能调用'); }, showPrice: function () { return new Error('Phone 抽象方法 showPrice 不能调用'); }, showColor: function () { return new Error('Phone 抽象方法 showColor 不能调用'); } } AbstractFactory.Pad = function () { this.type = 'Pad'; } AbstractFactory.Pad.prototype = { showType: function () { return new Error('Pad 抽象方法 showType 不能调用'); }, showPrice: function () { return new Error('Pad 抽象方法 showPrice 不能调用'); }, showColor: function () { return new Error('Pad 抽象方法 showColor 不能调用'); } } // 抽象工厂实现对抽象类的继承 function Iphone(type, price, color) { this.type = type; this.price = price; this.color = color; } //抽象工厂实现对 Phone 抽象类的继承 AbstractFactory(Iphone, 'Phone'); Iphone.prototype.showType = function () { return this.type; } Iphone.prototype.showPrice = function () { return this.price; } Iphone.prototype.showColor = function () { return this.color; } function Ipad(type, price, color) { this.type = type; this.price = price; this.color = color; } AbstractFactory(Ipad, 'Pad'); Ipad.prototype.showType = function () { return this.type; } Ipad.prototype.showPrice = function () { return this.price; } Ipad.prototype.showColor = function () { return this.color; } // 实例 var iphone5s = new Iphone('iphone 5s', 3000, '白色'); console.log('今天刚买了' + iphone5s.showType() + ',价格是' + iphone5s.showPrice() + ',' + iphone5s.showColor()) var iphone8s = new Iphone('iphone 8s', 8000, '白色'); console.log('今天刚买了' + iphone8s.showType() + ',价格是' + iphone8s.showPrice() + ',' + iphone8s.showColor()) var ipad = new Ipad('ipad air', 2000, '骚红色'); console.log('今天刚买了' + ipad.showType() + ',价格是' + ipad.showPrice() + ',' + ipad.showColor()) ``` **除此之外还有单例模式、适配器模式、装饰器模式、代理模式、观察者模式、迭代器模式等**
举报
分享

分享文章到朋友圈

分享文章到微博

采纳成功

您已采纳当前回复为最佳回复
发表于2021年03月27日 23:19:17
直达本楼层的链接
沙发
显示全部楼层

不错,感谢分享

点赞 评论 引用 举报

采纳成功

您已采纳当前回复为最佳回复
发表于2021年03月31日 14:12:17
直达本楼层的链接
板凳
显示全部楼层

感谢分享

点赞 评论 引用 举报

游客

富文本
Markdown
您需要登录后才可以回帖 登录 | 立即注册

结贴

您对问题的回复是否满意?
满意度
非常满意 满意 一般 不满意
我要反馈
0/200