架构训练营第二周作业
作业一:
1. 请描述什么是依赖倒置原则,为什么有时候依赖倒置原则又被称为好莱坞原则?
依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)。其核心思想是:要面向接口编程,不要面向实现编程。
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类。
使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。
2. 请用接口隔离原则优化 Cache 类的设计,画出优化后的类图。
作业二:
第二周课程总结
面向对象编程的本质和未来
行行色色的编程语言
汇编
Basic
Perl
C/C++
Java
....
编程语言的实质
编程的目的:用计算机来解决现实世界的问题
编程的过程:在计算机中与现实世界的建立联系
问题领域:包含与系统所要解决的问题相关的实物与概念的联系
抽象的种类
对基础机器的抽象:机器代码与汇编
对计算处理逻辑抽象:非结构化的高级语言(Basic,Fortran等)
对问题领域进行抽象:结构化程序设计
直接表达问题空间内的元素:面向对象的程序设计
面向对象
什么是面向对象
什么是对象
对象具有状态、行为和标识
面向对象编程的三要素(特征)
封装-隐藏细节
继承-接口的重用
多态-对象互换
面向对象设计的目的
强内聚、低耦合、从而使系统易扩展,更强壮,可移植,更简单。
软件设计的“臭味”
软件设计的最终目的,是使软件达到“强内聚、松耦合”,从而使软件:
易扩展-易于增加新的功能
更强壮-不容易被破坏
可移植-能够在多样的环境下运行
更简单-容易理解、容易维护
与之相反,一个“不好的”软件,会有如下问题:
僵硬-不容易改变
脆弱-只想改A,结果B被意外破坏
不开移植-不能适应环境的变化
导致误用的陷阱
晦涩-代码难以理解
过度设计、CP代码
糟糕代码的特点
僵化性:很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的改动。
如果单一的改动会导致依赖关系的模块中的连锁改动,那么设计就是僵化的,必须要改动的模块越多,设计就越僵化。
脆弱性:对系统的改动会导致系统中和改动的地方无关的许多地方出现问题。
出现新问题的地方与改动的地方没有概念上的关联。要修正这些问题又会引出更多的问题,从而使开发团队就像一只不停追逐自己尾巴的狗一样。
牢固性(Immobility):很难解开系统的纠结,使之成为一些可在其他系统中重用的组件。
设计中包含了对其他系统有用的部分,而把这些部分从系统中分离出来所需的努力和风险是巨大的。
粘滞性(Viscosity):做正确的事情比做错误的事情要困难。
面临一个改动的时候,开发人员常常会发现会有多种改动的方法。有的方法会保持系统原来的设计,而另外一些则会破坏设计,当那些可以保持系统设计的方法比那些破坏设计的方法跟难应用是,就表明设计具有高的粘滞性,作错误的事情就很容易。
不必要的复杂性(Needless Complexity):设计中包含有不具任何直接好处的基础结构
如果设计中包含有当前没有用的组成部分,他就含有不必要的复杂性。当开发人员预测需求的变化,并在软件中放置了处理那些潜在变化的代码时,常常会出现这种情况。
不必要的重复(Needless Repetition):设计中包含有重复的结构,而该重复的结构本
可以使用单一的抽象进行统一。
当 copy,cut,paste 编程的时候,这种情况就会发生。
晦涩性(Opacity):很难阅读、理解。没有很好的表现出意图。
代码可以用清晰、富有表现力的方式编写,也可以用晦涩、费解的方式编写。一般说来,随着时间的推移,代码会变得越来越晦涩。
OOD原则
开/闭原则(OCP)
对于 扩展 开放
对于 修改 封闭
简而意之:不需要修改软件实体(类、模块、函数等),就应该能够实现软件的功能。
如何实现不修改而扩展呢?
抽象
合理的面向对象设计
合理的设计模式组合
依赖倒置原则(DIP)
高层模块不能依赖底层模块,而是大家都依赖于抽象;
抽象不能依赖实现,而是实现依赖抽象
DIP倒置了什么?
模块或包的依赖关系
开发顺序和职责
Liskov替换原则(LSP)
在 Java/C++ 这样的静态类型语言中,实现 OCP 的关键在于抽象,而抽象的威力在于多
态和继承。
一个正确的继承要符合Lisvkov替换原则
简言之:子类型(subtype)必须能够替换掉它们的基类型(base type)。
从“契约”的角度来看 LSP
LSP 要求,凡是使用基类的地方,一定也适用于其子类。
从 Java 语法角度看,意味着:
子类一定得拥有基类的整个接口;
子类的访问控制不能比基类更严格;
继承和组合是 OOP 的两种扩展手段
继承的优点:
比较容易,因为基类的大部分功能可以通过继承直接进入子类。
继承的缺点:
继承破坏了封装,因为继承将基类更多的细节暴露给子类。因而继承被称为“白盒复用”;
当基类发生改变时,可能会层层影响其下的子类;
继承是静态的,无法在运行时改变组合;
类数量的爆炸。
应该优先使用组合
单一职责原则(SRP)
又被称为“内聚性原则(Cohesion)”,意为:一个模块的组成元素之间的功能相关性
将它与引起一个模块改变的作用力相联,就形成了如下描述:一个类,只能有一个引起它的变化的原因。
接口分离原则(ISP)
案例分析-Flower
源码地址:
https://github.com/zhihuili/flower
程序是如何运行又是如何崩溃的
Flower 实现异步的基础是 Akka 的 Actor
评论