重构- 关于可读性、原则和模式 中国网站技术部-市场开发部-前端(魏琪君) UED Team Design
主要内容 可读性 原则和模式
可读性-形 向下规则 方法短小,缩进层次不超过 3
缩进
摘录《代码整洁之道》 在 20 世纪 80 年代,常说函数不该长于一屏(那时候显示屏分辨率低,只有 24 行) 函数应该有多短小 ?  通常来说,应该短于代码清单 3-2 中的函数 ,  代码清单 3-2 实在应该缩短成代码清单 3-3 这个样子 我数了数清单 3-2 ,代码行数是 14 行, 而 3-3 是 6 行, 而且是包含最后的大括号的
摘录《软件开发沉思录》 方法只使用一级缩进 拒绝使用 else 关键字 一句代码只有一个 '.' 不要使用缩写
可读性-意 统一词汇 书写方式
统一词汇 doc , header, content, footer tag, alitalk, dialog, topbar http://fd.aliued.cn/doc/page/.personal/qijun.weiqj/design/wp.png http://fd.aliued.cn/doc/page/.personal/qijun.weiqj/design/offer-chooser.png
使用同样的词汇书写和交流
action 希望我们有一个丰富的词汇库 组件化从统一词汇做起
如何去写代码 围绕我们用词汇建立的对象,用代码描述它和对它们的操作 从整体到局部,从抽象到具体,建立不同层次 让每一层次简单(认知超载)
一个例子:选择产品组件 http://fd.aliued.cn/doc/page/.personal/qijun.weiqj/design/offer-chooser.png
需求 1: OfferChooser 可以渲染在任意节点上
需求 2 :使用 OfferChooserDialog ,可以以对话框的形式使用
OfferChooser 由两部分组成
SourceOfferPart 主要由三部分组成 SearchPanel, OfferList, PagingNav
SearchPanel 由一个自定义的类目下拉框和普通的搜索功能组成
SelectedOfferPart
问题? 每个类各司其职,做自己份内的事,因为自己的功能比较少,所以相对也会比较简单 1.  类和类之间肯定有依赖,肯定有通信,那如何解决? 2.  开始仅知道必须要有  ChooserOffer 类和  ChooserOfferDialog 类, 因为这是由需求决定的。 那  SearchPanel, PagingNav 等类 我怎么想得到呢 ?  不能全部都写在一个类中吗?
坏味道 1 :长且重复的方法名
提取,形成 SearchPanel
现在的 ChooserOffer
代码行数和类数量 平均方法代码行数: 25 行 类中方法数量:保持 8 个以内 原则:单一职责原则( SRP )
原则和模式 刚才的未解决问题: 类和类之间肯定有依赖,肯定有通信,那如何解决?
类和类的关系 1.  继承 2.  组合
类图
继承-单例
继承-多例
组合
原则 优先使用组合,而不是继承 ( prefer composition over inheritance ) 继承带来很强的耦合性,特别是在强类型语言中 在 JS 中,继承的耦合会低一些
根据 耦合性 对继承进行分类 子类仅依赖父类的公有方法
根据 耦合性 对继承进行分类 子类依赖父类的非公有方法 ( 重写或调用父类的保护级方法 )
更适合 JS 的原则 “ 优先使用组合,然后再是第 1 类继承 ,  慎重使用第 2 类继承” 应该记住的: 一个类能否被继承是一个设计问题,而不是捡到便宜 除此外: 继承是否合理是否必要,可以看原则: LSP (里氏替换原则)
稳定依赖原则( DIP ) 解决依赖性 实际上这个原则被称为 “依赖倒置原则”, 为了更好地理解,我弱化了这个原则 “ 模块应该依赖于比它更稳定的模块” 思考: fdev4, core, widget, ui-core global/module/page,  页面组件
[摘录]《敏捷软件开发,原则模式和实践》 a. 高层模块不应该依赖于低层模块。二者都应该依赖于抽象 b. 抽象不应该依赖于细节。细节应该依赖于抽象。
问题? 那稳定的类要调用非稳定的类,或者模块和模块之间需要通信怎么办 ? 我们引入一个中间层(思考  $.ajax 的回调和 自定义事件)
实现
依赖注入( DI )
实际应用 OfferChooser ,点击 SourceOfferPart .select, SelectedOfferPart 需要做一些事
引入间接层:使用自定义事件
题外话 有时候整个页面中的交互,我们可以使用触发在 window 上的自定义事件
开放封闭原则( OCP ) 解决扩展性 “ Closed for Modification; Open for Extension” 对变更关闭,对扩展开放
解析 OCP 我们应该把模块写成:  只要添加代码就能完成扩展, 而不需要修改原来的代码 这个原则不是教我们怎么做, 而是教我们做成怎么样。
一个例子
再一个例子
问题 难道我一开始就写成那样吗? OCP? 重构:受一次伤原则
总结 方法组成代码“一级结构”。 长度短,名称精炼,向下规则 类以及类之间的关系,组成代码的“二级结构” 五大原则( DIP , OCP , LSP , SRP ),以及我们未接触的 ISP 优先使用组合等 类和类形成包,包以及包之间的关系,组成代码的“三级结构” 遵循共同的原则: 简单
模式新视角
设计模式是一套词汇 我们对 Offer 进行一个排序,只要实现这个 Compare 接口就行了, 我们原来有这样的实现的,只是接口形式不一样,所以我们做个 Adapter 就好了 我们在取数上引入了 cache ,但我想让调用方透明,我们引入一个 Proxy... 我们还是要使用原来的那些方法的,但是太多了,我们做一个小小的 Facade,  这样我们就不用管原来那堆东西了 矣~~,这个类构造太麻烦了,弄个 Factory 方便构造,同时把依赖注入,  还有还有, 这两个类的依赖不行,使用一个接口或者 Observer 反转一下依赖 嗯,这一系列操作,我们把它弄成一个一个 Command 序列化掉 ... 存起来,下次恢复再执行 这个验证框架扩展起来不是很方便,验证逻辑其实就是一个一个 Strategy 嘛, 改改~~
重意不重形 看一个模式时,只要看它的“意图”,“遵循的原则”,还有“名称” 稍微看一下实现,看看能否用其他更优雅的实现,然后把类图和实现忘掉 使用时,突然感觉到自己正在使用某种模式, 这样就可以了。 即不经意间使用模式 重要的是知道什么时候不使用它
最后一个例子 http://fd.aliued.cn/doc/page/.personal/qijun.weiqj/design
画出类图
策略( Strategy 或 Policy) 原则? 开放封闭原则 OCP 依赖倒置原则 DIP 单一职责原则  SRP (一个类只有一个引起它变化的原因) 优先使用组合,而不是继承 prefer composition over inheritance
回顾 可读性 形: 方法小,向下规则 意: 词汇, 分层描述 原则 依赖倒置(稳定依赖)原则  DIP 开放封闭原则  OCP 优先使用组合 重构 提取方法形成类 受一次伤原理 模式 设计模式是一套用于交流的词汇 策略模式 (Strategy)

魏琪君-重构-关于可读性、原则和模式