引言:

相较于后端,由于开发成果的即时可见,前端很容易为了体验到一个需求实现,阶段性胜利的快感而“不择手段”,这虽然有助于我们提高积极性,获取成就感,但也导致了我们很多时候只在意结果,不注重过程,陷入面向过程开发的思维误区,这导致了我们在后续拓展中步履维艰

因此,作为一个成熟的前端应当具备系统化的设计思路,以及前瞻性的眼光去考虑后续迭代升级中可能遇见的问题,而学习设计模式正好能实现这一目的

本文将选取主流框架以及实战案例中的设计思路进行分析,希望读完文章能给大家带来收获

概念:

设计模式即是前人代码设计经验的总结,并给予后继者作为设计思路的参考,其中涵盖创建型、结构型、行为型共三类二十三种,文章将会选取前端应用中常用的模式进行解读

特征:

面向对象,高内聚,低耦合,即是 SOLID 五大原则:

1. 单一职责原则(SRP):接口功能单一,不承担过多的职责(各司其职√,越俎代庖×)

2. 开放封闭原则(OCP):关闭内部修改,开放外部扩展(与其牵一发而动全身,不如开疆扩土海阔天空)

3. 里式替换原则(LSP):派生的子类应当能够替换基类,即派生的子类均继承基类的功能,且不修改基类行为的期望(百花齐放√,南辕北辙×)

案例(1):手机作为常用工具,可以用来拨打电话,发送信息,浏览网站,游戏娱乐。请问以下选项中可以替代“手机”一词的有?
 A.OPPO手机                          B.华为手机                          C.小米手机                          D.苹果手机

解析:上述问题中各品牌手机作为手机派生的子类,均能实现手机所拥有的所有功能,且不改变这些功能原本的期望(目的),故而符合里式替换原则

案例(2):已知某类动物的叫声的作用包括求偶,示警,示威。请问以下属于该类动物叫声的选项有?
 A.虎啸                                   B.狮吼                                   C.狼嚎                                   D.喵喵叫

解析:虎啸、狮吼、狼嚎均属于该类动物的叫声,而喵喵叫虽然也是叫声,但是猫咪喵喵叫的行为是对主人的信息传达,并不属于求偶,示警,示威中的一种,因此行为期望(目的)与基类不符,故而不属于该类动物,即不符合里氏替换原则

4. 接口隔离原则(ISP):不应该强迫用户依赖于它们不用的方法,即某个接口中不应含有用户无需的副作用(画蛇添足×,庞然大物×)

解释:接口应当最小颗粒化,即一个功能齐全的总接口应尽可能拆分成多个小接口,每个接口仅服务于一个子模块,因为过大的接口,虽说可以实现更多的功能,但往往复杂度更高,也更易耦合,或是掺杂客户无需的功能,当原有的功能修改时,又可能导致其它功能的同步修改,因此一对一的小接口要胜过一对多的大接口

5. 依赖倒置原则(DIP):高层模块不应当依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象

由于JS是动态语言,所以不需要为了解耦而去抽象,所以暂且忽略这句话中有关抽象的部分,当然感兴趣的同学也可以去学习一下Typescript,了解其中的 interface 与 implement

高层模块不应该依赖低层模块

如果某个模块依赖其他模块的实现,那么消费其他模块的模块就是高层模块,被其他模块消费的,则是低层模块(在这句话中,消费与依赖、引用意思相近)

上述的内容咋一看确实不太好理解,下面用通俗的例子来解释

// 多种类型的商品
class Icecream {constructor(){console.log('我是雪糕,需要放在冰柜')}
}
class Rice {constructor(){console.log('我是大米,需要放在食品区')}
}
class Box {constructor(){console.log('我是盒子,需要放在生活区')}
}// 我拥有的一家商店
class Store {constructor(){ // 每天开工的时候我都会批量进货,并将它们摆放到对应的区域const icecream = new Icecream() // 雪糕在此处被引用(依赖),所以雪糕是低层模块this.putIcecreamIntoFreezer(icecream)  const rice = new Icecream() // 同理,大米是低层模块this.putRiceIntoFoodArea(rice) const box = new Box() // 同理,盒子也是低层模块this.putBoxIntoShelves(box) // 而因为商店依赖于这些商品,所以商店是高层模块}putIcescreamIntoFreezer(icecream){// ... 将雪糕放入冰柜}putRiceIntoFoodArea(rice){// ... 将大米放进食品区} putBoxIntoShelves(box){// ... 将盒子放入生活区货架上}
}

上述代码确实可以实现目前采购商品并放置货架的需求,但每当引入新的商品时,我们又要在Store的构造函数中添加创建商品对象的步骤,并为它们添加放置进商品区的方法,这违背了我们上面讲过的开放封闭原则,所以接下来我们将对它进行改造,实现依赖倒置

class Store{static commodityMap = new Map() // 进货清单static purchase(commodity){// 第二步:将货物收录到进货清单中,即实现依赖注入 Store.commodityMap.set(commodity.name,commodity) } constructor(){// 第三步:遍历第二步得来的进货清单for(let commodity of Store.commodityMap){// 第四步:将放置商品的方法传给商品模块// 并调用它们的 move 方法,让商品们自己跑到自己的区域内commodity.move(this.putInto.bind(this)) } }putInto(commodity,area){// 第六步:将货品放入指定的区域内}
}const store = new Store() // 商店开工---------------------------------------------------------class Icecream { area = '冰柜' // 存放的位置name = '雪糕' // 进货清单的索引  move(callback){// callback 是 store 的 putInto 方法callback(this,this.area) // 第五步:根据自身类别决定放置区域}
}Store.purchase(new Icecream()); // 第一步:进货雪糕 ---------------------------------------------------------class Rice { area = '食品区'name = '大米'  move(callback){// callback 是 store 的 putInto 方法callback(this,this.area) // 第五步:根据自身类别决定放置区域}
}Store.purchase(new Rice()); // 第一步:进货大米

这时候我们再想进货其它商品时,只需要通过 Store.purchase 方法去采购货物,而无需再修改 Store 这个高层模块,因此我们通过依赖注入的方式实现了依赖倒置,使得高层模块不再依赖于低层模块

6. 最少知识法则(迪米特法则):一个对象应尽可能对其它对象有最少的了解,类应该与其协作类进行交互但无需了解它们的内部结构

解释:减少对象之间不必要的联系

// 我是一名新司机
class Driver {myCarconstructor (car) {this.myCar = car // 我从汽车4s店内购买了一辆汽车}drive () { this.myCar.engine.start() // 我在驾驶前需要启动引擎// 重点,我调用了汽车的引擎的开启方法,除了myCar的方法外,我还需要了解engine中的方法}
}class Car {engine constructor (engine) {this.engine = engine  // 我是一辆汽车,出厂时装配了一台引擎}
}class Engine {start () {console.log('我是汽车引擎,我正在启动')}
}const engine = new Engine()
const car = new Car(engine)
const driver = new Driver(car).drive()

如上述代码所示,我作为一名普通的汽车驾驶员,却要知晓引擎的启动方式,这明显有违常理,也违反了最小知识法则,即我被强迫去了解我不需要知道的知识,既增加了我的学习成本,也增加了多个类之间耦合度

所以我们对代码进行修改:

// 我是一名新司机
class Driver {myCarconstructor (car) {this.myCar = car // 我从汽车4s店内购买了一辆汽车}drive () {this.myCar.start() // 我通过汽车的一键启动功能直接启动引擎}
}class Car {engineconstructor (engine) {this.engine = engine  // 我是一辆汽车,我装配了一台引擎}   start () {this.engine.start() // 作为一辆现代化的小汽车,我拥有一键启动功能}
}class Engine {start () {console.log('我是汽车引擎,我正在启动')}
}const engine = new Engine()
const car = new Car(engine)
const driver = new Driver(car).drive()

修改后,驾驶员只需要使用汽车的一键启动功能直接启动引擎,而不再需要了解引擎的原理,这即是最小知识法则

第一类 创建型模式:

工厂方法模式(工厂模式):

在讲解工厂方法模式之前我们需要先了解简单工厂模式

简单工厂模式:将创建对象的过程使用一个通用的工厂模块封装

情景剧场

“阿珏,你过来一下,我有事找你。”

“啊,产品姐姐,又有新需求了吗?”(看着oa中堆了好几页的需求,我不禁落下了幸福的泪水)

“对的,我们准备新建一个项目,至于做什么我还没想好,不过肯定需要登录功能,你先把登录页面做出来看看吧。”

从实战思路学习前端的设计模式相关推荐

  1. 零基础的同学看过来,如何系统学习前端,只要你掌握了,学习web前端的思路就打开了,为以后成为高级前端工程师做一个铺垫

    软件开发工程师在行业外大众的眼里, 或许是一个出众的职业,收入不低, 技术含量还挺高,就连我自己刚入行时也是这么认为的,但事实上并不确切.任何行业中,只要是在金字塔顶端的那部分,都是令人羡慕的,然而, ...

  2. 如何高效学习前端新知识,我推荐这些~

    众所周知,关注公众号可以了解学习掌握技术方向,学习优质好文,落实到自己项目中.还可以结交圈内好友,让自己融入到积极上进的技术氛围,促进自己的技术提升. 话不多说,推荐这些优质前端公众号 前端之神 10 ...

  3. 新手小白该怎么学习前端?附学习路线和资料

    初学编程的小伙伴经常会遇到的问题,1.没资源 2.没人带 3.不知道从何开始 ,小编也是从新手期过来的,所以很能理解萌新的难处,现在整理一些以前自己学习的一些资料送给大家,希望对广大初学小伙伴有帮助! ...

  4. 如何跨行学习前端?一个小白的跨行之路~

    如何跨行学习前端?一个小白的跨行之路~ 此篇文章讲述了一个小白跨行学习前端过程遇到的问题,以及是如何解决的.希望此篇文章能够帮助到更多的人. 前端小白该如何入门?(先给大家分享**干货**最后在讲故事 ...

  5. 前端搬运工 零基础的前端开发初学者应如何系统地学习 前端掌握技能的学习路线

    前端小伙伴们:[刚入门,但迷茫人群],请认真读完 下面的 淘宝web 大神总结,如果你对前端是真爱的话,并且坚信可以作为职业去改变你的生活,慢慢日积月累,按这个来吧,真的! 上半部分是 技术路线, 下 ...

  6. 解答关于学习前端的一些问题

    关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 github:链接 前言 最近在公众号和文章中经常会收到一些读者的留言和评论,本文是我挑选的一些在关于学习 ...

  7. 学习前端你必须看过这几本书!

    总是觉得学习前端很难? 那我告诉你,除了掌握学习路线和学习方式外,你还需要好好看看这几本书-- Unix编程艺术 作者:[美] Eric S·Raymond 原作名:The Art of UNIX P ...

  8. 《Angular4从入门到实战》学习笔记

    <Angular4从入门到实战>学习笔记 腾讯课堂:米斯特吴 视频讲座 二〇一九年二月十三日星期三14时14分 What Is Angular?(简介) 前端最流行的主流JavaScrip ...

  9. 如何高效学习前端新知识,拓展视野,我推荐

    技术日新月异,发展迅速,作为一个与时俱进的互联网人,需要不断地学习扩宽视野. 今天为大家推荐几个技术领域中出类拔萃的公众号,它们的每一篇推文都值得你点开! 1 前端开发爱好者 学习路线 数据结构算法  ...

  10. 碎片时间学习前端,我推荐这些~

    大家好,我是若川.祝大家中秋节快乐. 前端技术日新月异,发展迅速,作为一个与时俱进的前端工程师,需要不断的学习. 这里强烈推荐几个前端开发工程师必备的优质公众号,希望对你有所帮助. 大家可以像我一样, ...

最新文章

  1. linux配置本地yum源 centos7.9为例
  2. Java程序优化之享元模式
  3. admin 系统被嵌套在第三方系统中的跨域异常
  4. flink报错;IllegalArgumentException: requirement failed The class xx$3 is an instance class, mean
  5. 表单元素的外观改变(webkit and IE10)
  6. netstat命令详解
  7. java实现时间轮定时器_基于侵入式链表的时间轮定时器实现
  8. 如何压缩视频大小?详细操作步骤
  9. 无盘服务器磁盘4k对齐,4K对齐:Win7磁盘管理分区教程_硬盘_内存硬盘技巧-中关村在线...
  10. 创业公司的股权分配 .
  11. Hive数据库创建表
  12. php 如何让验证码刷新,php实现点击可刷新验证码_php技巧
  13. dojo初解和dojo.connect用法(转)
  14. 怀念到哭泣、再美也伤
  15. 互联网公司招聘--大众点评--产品岗--2015年笔试题
  16. Henry前端笔记之 git实际操作问题记录
  17. 向服务器写入文件失败,向远程服务器写入文件
  18. 碳排放zc汇总、碳排放权交易、省级碳排放效率、环保数据集(2007-2022年)
  19. ssh mysql jsp码头船只出行及配套货柜码放管理系统的设计与实现+论文+开题报告+任务书
  20. [多图试用]WPS Office for Mac 轻装上阵与诚意而来

热门文章

  1. Cron在线表达式生成器
  2. 1、项目搭建、本地视频列表展示
  3. Action-Net|UCF101数据集上训练测试数据load过程
  4. android Textview属性细节以及EditText属性
  5. 老友记第一季自学笔记01
  6. iphone投屏老是显示无法连接服务器,iphone怎么投屏到电视 升级iOS11后为什么投屏会失败...
  7. excel抽奖软件作弊_使用Excel下拉列表防止作弊
  8. HTTP协议发展历史
  9. 研发体系核心代码和文档安全保护方案
  10. Photoshop插件-证件照-白红蓝底-PS插件-脚本开发