后端基础

《架构师训练营》之OOP

2020-06-17  本文已影响0人  anOnion

极客时间《架构师训练营》第二章学习笔记

软件开发简史

  1. 莱布尼兹最早提出:各种事务都可以通过一种语言进行描述
  2. 十九世纪,Ada 写出了第一个软件程序
  3. 冯诺依曼在计算机上输入了第一个程序
  4. 之后出现了形形色色的编程语言,直到面向对象语言出现

OOP & Design Patterns

面向对象有三要素:封装、继承、多态。面向对象编程不是简单地使用面向对象语言编程,而是利用多态编程——将客观世界的对象抽象为领域内的对象。

我个人就是在校期间修完了 java 课的学分,但是完全没有理解 OOP 的魅力,直到后来看了《Head First:Design Pattern》。设计模式就是一种应用面向对象语言解决现实问题的经验汇总。

框架 v.s. 工具

它俩的区别:框架调用应用内的代码,工具被应用内的代码调用。我曾看过一本叫《演进式架构》的书,这里提到了一个应对框架和工具版本升级的策略;该作者认为,我们应该尽早地升级框架,但是尽可能不升级工具的版本。

我自己是写前端开发的,前端框架升级非常频繁;只需半年,整个框架的使用方法就会发生翻天覆地地变化。我曾在一个叫 vuetify 的 UI 框架上吃过亏。我之前的认知是尽量不要升级版本,因此有将近一年没有升级 vuetify 框架;但是在这期间 vuetify 增加了许多新的 feature。我厂的设计组一直是依赖 vuetify 官网的 UI 组件设计业务的,某天他们提了一堆新的设计,但是很多组件老版本并不支持,我们自己实现又困难重重,所以我想到了升级 vuetify。但是升级后错误满屏,花了很长时间才解决问题。解决方案最后是在一个很久没人访问的 issue 里找到的。后来我总结到:现代框架升级太快、信息太多,假如某个版本升级后出现了问题,很快就会有人提出并修复,之后又很快会被人遗忘;若数月后再升级,这些“错误记忆”将淹没在信息的大海中,你可能再也找寻不到解决之道。错失升级版本的时间窗口很可能导致灾难性的后果,所以还是尽量早升级框架,以免过多的技术债务。

“电话拨号软件”案例分析

软件设计的臭味:僵硬、脆弱、不可移植、晦涩、过度设计等等。

老师在课上以一个“电话拨号软件”为案例,解释了“臭味”软件——不可扩展。这种软件的的最大特点就是当新增需求时,只能够通过添加 if-else、switch-case,或是一系列的全局变量修修补补;代码从阅读感官上就及其难看、数量巨大后几乎没有可维护性。解决之道,就是在写代码时应用设计模式,避免使用 if-else。

特别同意老师的一句话——“不需要写 else”。我自己每天都会 code review 别人的代码,也经常抓人家的 if-else 语句,特别是那种两层以上的 if-else 嵌套,全部都会打回重写。程序员要为自己的工作负责,不应该整天写一些垃圾代码。但是项目中依旧有很多的 if-else 层层嵌套(七八层也很常见)。避免这种代码要从项目一开始就达成共识,不然垃圾堆积起来,也就没人理会“代码整洁之道”了,这就是所谓的“破窗效应”吧。

面向对象设计的基本原理

避免代码“臭味”,最根本的指标就是所谓的“高内聚、低耦合”,通常来说就是遵守SOLID原则:

单一职责(SRP)

单一职责表明一个类有且只有一个职责。一个类自然能添加任意多的属性和方法,然而过多的内容会让这个类变得笨重。我个人觉得多少倒是次要的,只是过多的内容很容易导致一系列副作用——牵一发而动全身。所以保持较小的类,仅仅负责单一职责,通过测试后就可长期“保鲜”。

开放闭合原则(OCP)

开闭原则指出一个类应该对扩展开放、对修改闭合。通俗来说就是:一旦创建了一个类,你的方法就会有人调用,之后你就尽量不要再修改该方法了,因为很可能会导致一系列的副作用。所以一般只扩展新的功能而不是修改旧功能。我个人实际开发中会逐渐地用新方法替换掉旧方法(甚至是新类替换旧类),最后将不再被使用的旧方法删除,保持代码整洁。

里氏替换原则(LSP)

里氏替换原则指的是:派生的子类应该可以替换父类,也就是说任何父类可以出现的地方,子类一定可以出现。换言之,父类的约束要强于子类。现实开发中要慎用继承,一般情况下就是用组合来代替继承。

接口分离原则(ISP)

接口隔离原则:类不应该被迫依赖它们不使用的方法,接口应该拥有尽可能少的行为,需要精简单一。这期的命题作业第三小题就是很好的例子,Cache 实现类被两个不同的应用调用,但是 Cache 对这两个应用暴露的方法是不一样的,所以可以通过 implements 两个接口实现方法隔离。

依赖倒置原则(DIP)

依赖倒置原则表明高层模块不应该依赖低层模块;相反,它们都应该依赖抽象或接口。这意味着你不应该在高层某块里依赖具体的低层实现类,因为这样会让高层某块紧耦合低层模块;如果某天修改低层某块,很可能导致高层模块奔溃。

其实只要经常写单元测试的人,很容易发觉依赖倒置“真香”:只要使用 mock 依赖,高层模块就可以跑通测试了;不然,随便一修改低层模块,各种单元测试就报错了。

现实中开发,一般会用控制反转(IoC)技术,通过构造器传参(低层模块)的形式初始化高层模块;具体到开发框架中就是所谓的依赖注入(DI)了。

小结

这周的内容主要是利用一个拨号软件的案例,回顾了一下 Robert C. Martin 的 SOLID 原则。在代码设计阶段,只要时刻保持 SOLID 原则,就可以避免写出一系列的垃圾代码,保证代码持续可维护。我还看过 Martin 的另一本书《Clean Architecture》,他提到在架构设计中也是同样的 SOLID 原则。道理是互通的,整洁的系统才能减少我们工作中的编码痛苦,实现系统更低价的维护成本。

上一篇下一篇

猜你喜欢

热点阅读