javascript-设计模式与开发实践三

设计原则和编程技巧 可以说每种设计模式都是为了让代码迎合其中一个或多个原则而出现的,它们本身已经融入了设计模式之中,给面向对象编程指明了方向。 前辈总结的设计原则通常值的是单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、合成复用原则和最少知识原则。 单一职责原则(SRP) SRP原则体现在:一个对象(方法)只做一件事情。如果一个方法承担了太多的职责,并且这些职责耦合在一起,一个职责发生变化影响到另外的职责的实现。这种耦合性得到的是低内聚和脆弱的设计。如果两个职责总是同时变化的,那么也不必一定要分离他们。有时即使耦合在一起,但没有发生改变的征兆,那么也许也可以不必主动分离他们,而是等到需要重构的时候。有时候为了方便性,我们可以选择违反规则,去牺牲稳定性。比如 jQuery 的 attr 方法,内部实现很复杂庞大,维护会有一些困难,但对于使用者很方便。优缺点 优点是,降低了单个类或者对象的复杂度,有助于代码复用和进行单元测试。当一个职责需要改变的时候,不会影响到另外一个职责。缺点是,增加代码复杂度,增加了对象之间相互联系的复杂度。 最少知识原则(LKP) LKP 说的是一个软件实体应当尽可能少地与其它实体发生相互作用。设计模式中的体现: 中介者模式(增加一个中介者对象,让所有相关的对象都通过中介者对象来通信) 外观模式(隔离客户与复杂子系统的之间的联系,客户不用去了解子系统的细节) 原则只是一种指导,要根据具体的环境来决定是否遵守。 开放-封闭原则(OCP) 软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。 开放和封闭:比起修改源代码,增加代码是成本更低,且更不容易出 bug 的方式。 利用对象多态性消除条件分支。 找出变化的地方,封装变化,可以把系统中稳定不变的部分和容易变化的部分隔离开来。 最初编写代码的时候,因为需求排期不是无限的,可以先假设变化永远不会发生,这样有利于迅速完成需求。当变化发生且对我们接下来的工作造成影响了,可以回过头来封装这些变化的地方,然后确保我们不会掉进同一个坑里。 接口和面向接口编程 通常讲到的接口 API 接口,主动暴露接口来通信。 一些语言提供的关键字,比如 Java 的 interface。 更加抽象,接口时对象能响应的请求的集合。 传统的面向对象语言比如 Java,会有抽象类和 interface 来限制,而 JavaScript 是一个动态类型语言,类型本身在 JavaScript 是一个相对模糊的概念。可以认为,JavaScript 中的非基础类型都可以看成“天生”被“向上转型”成了 Object。因为不需要进行向上转型,接口在 JavaScript 中的最大作用就退化到了检查代码的规范性。在 JavaScript 中,我们一般会手动编写一些接口检查的代码。 代码重构 1、提炼函数 需要重构的函数:如果一个函数过长,并且需要很多注释才能让这个函数显得易读一些。将可以独立出来的代码拿出来放进另一个独立的函数,有以下好处: 避免出现超大函数。 独立出来的函数有助于函数复用。 独立出来的函数更容易被覆写。 独立出来的函数如果有一个良好的命名,它本身就起到到了注释的作用。 2、合并重复的条件片段 3、把条件语句提炼成函数 比如: age > 50 && gender = 'woman' 改成 isOldWoman() 4、合理使用循环 如果有些代码负责的是一些重复性的工作,那么可以使用循环完成同样的功能。 5、提前让函数退出代替嵌套条件语句 6、传递对象参数避免过长的参数列表 7、尽量减少参数数量 8、少用三目运算符 条件分支逻辑简单时,可以使用三目运算符,但是如果条件分支逻辑非常复杂,则用if、else会更合适,因为阅读更加容易,且方便修改。 9、合理使用链式调用 链式调用的时候,虽然可以节省一些中间变量。但带来的坏处时在调试的时候非常不方便,如果一条链中有错误出现,我们必须得先将这条链拆开才能加上一些 log 或者增加断点。除非链条相对稳定,且不容易发生修改,否则还是选择使用普通调用的形式。 10、分解大型类 面向对象设计鼓励将行为分布在合理数量的更小对象之中。把行为委托给这些其它类的对象来执行。 11、用 return 推出循环

March 13, 2021 · 1 min · vdorchan

javascript-设计模式与开发实践二

设计模式 单例模式 单例模式的定义是:保证一个类只有一个实例,并提供一个访问它的全局访问点。传统面向对象语言中,单例对象一般从“类”中创建而来。但 JavaScript 是一门无类(class-free)语言,创建对象的方法很简单,先创建一个“类”,其实很没必要。按照上面其定义,虽然全局变量不是单例模式,但在 JavaScript 中我们经常会把全局变量当成单例来使用,但要留意命名空间污染,它很容易被覆盖。 var a = {}; 惰性单例 惰性单例指的是在需要的时候才创建对象实例,是单例模式的重点。 var createDiv = (function () { var div return function () { if (!div) { div = document.createElement('div') div.style.display = 'none' document.body.appendChild(div) } return div } })() // 根据单一职责原则,可以写个通用的 var getSignle = (function (fn) { var result return function () { return fn || (result = fn.apply(this, arguments)) } })() 策略模式 策略模式的定义是:定义一系列的算法,把他们一个个封装起来,并且是他们可以相互替换。一个基于策略模式的程序至少由两个部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。例子:缓动动画 Tween、表单验证P86。计算年终奖的代码:...

March 13, 2021 · 3 min · vdorchan

javascript-设计模式与开发实践一

基础知识 前言 设计模式是在某种场合下对某个问题的一种解决方案。 在我们试图解决一些问题的时候,说不定别人也遇到过一样的问题,并且把他们整理成了模式,提供了一种通用的解决方案。 设计模式实际上是解决某一种问题的一种思想,与具体的语言无关。 除了主流的面向对象语言,在函数式的语言中,设计模式依然存在。 一些设计模式的实现会因为语言的不同而不同。 软件的成本并非全部在开发阶段,虽然设计模式可能会增加复杂度,或带来一些额外的代码,但它会让人们写出可复用和可维护性高的程序。 所有设计模式的实现遵循一条原则:“找出程序中变化的地方,并将变化封装起来”。 很多模式的类图和结构很相似但不重要,辨别模式的关键是这个模式出现的场景,以及帮助我们解决了什么问题。 一、面向对象的 JavaScript JavaScript 没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承。 ES6 的 class 是语法糖。 编程语言类型和鸭子类型 编程语言按照数据类型大体可以分为两类,一类是**_静态类型语言_**,另一类是**_动态类型语言_**。**_静态类型语言_**在编译时便以确定变量的类型,而**_动态类型语言_**要到程序运行的时候,待变量被赋予某个值之后,才会具有某种类型。** **静态类型语言**的优点是可以提早发现错误,编译器可以针对这些数据类型的信息做一些优化。缺点是强契约不够灵活。 _动态类型语言_的优点是简洁代码量少,缺点是有些类型相关的错误可能到运行的时候才能知道。 JS 是_**动态类型语言。**_ _鸭子类型_强调关注对象的行为,而不是对象本身。动态类型语言 不必借助超类型的帮助,假如一个对象正确实现了 push 和 pop 方法,那它就可以被当作栈来使用。 多态 多态的思想是把“做什么”和“谁去做”分离开来。下面代码,我们不关注传进来的是那种对象,只要它有 makeSound 方法。 // 不变的部分 function makeSound (animal) { animal.sound() } // 可变的部分 const Duck = function () {} Duck.prototype.sound = function () { console.log('嘎嘎嘎') } const Chicken = function () {} Chicken....

March 12, 2021 · 2 min · vdorchan