Week 2 命题作业及总结

用户头像
阿泰
关注
发布于: 2020 年 09 月 27 日

作业1:请描述什么是依赖倒置原则,为什么有时候依赖倒置原则又被称为好莱坞原则?

(以下答案摘自知乎https://zhuanlan.zhihu.com/p/148297604

依赖倒置原则是指高层模块不要依赖低层模块。高层模块和低层模块应该通过抽象来互相依赖。除此之外,抽象不要依赖具体实现细节,具体实现细节依赖抽象。

总结起来主要有以下两点:

1.高层模块不应该依赖底层模块,二者都应该依赖抽象。

2.抽象不应该依赖具体实现,具体实现应该依赖抽象。



“不要给我们打电话,我们会给你打电话(don‘t call us, we‘ll call you)”这就是著名的好莱坞原则。在好莱坞,演员把简历递交给演艺公司后就只有回家等待。由演艺公司(高层)对整个娱乐项的完全控制,演员(底层)只能被动式的接受公司的差使,在需要的环节中,完成自己的演出。所以依赖倒置原则也被称为好莱坞原则,如Tomcat、Spring都是基于这个原则设计出来的,应用程序(底层)不需要调用Tomcat或者Spring(高层)这样的框架,而是框架调用应用程序。

举例:

Tomcat 是运行 Java Web 应用程序的容器,我们编写的 Web 应用程序代码只需要部署在Tomcat 容器下,便可以被 Tomcat 容器调用执行。按照之前的划分原则,Tomcat 就是高层模块,我们编写的 Web 应用程序代码就是低层模块。Tomcat 和应用程序代码之间并没有直接的依赖关系,两者都依赖同一个“抽象”,也就是 Servlet 规范。Servlet 规范不依赖具体的 Tomcat 容器和应用程序的实现细节,而 Tomcat 容器和应用程序依赖 Servlet 规范。



作业2:请用接口隔离原则优化 Cache 类的设计,画出优化后的类图

提示:cache 实现类中有四个方法,其中 put get delete 方法是需要暴露给应用程序的,rebuild 方法是需要暴露给系统进行远程调用的。如果将 rebuild 暴露给应用程序,应用程序可能会错误调用 rebuild 方法,导致 cache 服务失效。按照接口隔离原则:不应该强迫客户程序依赖它们不需要的方法。也就是说,应该使 cache 类实现两个接口,一个接口包含 get put delete 暴露给应用程序,一个接口包含 rebuild 暴露给系统远程调用。从而实现接口隔离,使应用程序看不到 rebuild 方法。

回答:



总结:

本周主要对架构一些相关原则进行学习掌握,对于反应式编程框架 Flower还有待消化。

学习笔记

以下学习笔记摘自简书https://www.jianshu.com/p/b7e4fed57e60

软件开发简史

  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)了。



用户头像

阿泰

关注

还未添加个人签名 2018.04.28 加入

还未添加个人简介

评论

发布
暂无评论
Week 2 命题作业及总结