架构师训练营第 1 期 -Week2 - 框架设计学习总结
这周的学习收获很多,以前不明白的几个面向对象设计原则,在老师的讲解下豁然开朗。很佩服老师的学习方法,对知识掌握的深度。
上周讲了什么
上周主要讲了架构师的职责,必备能力,架构方法,4+1 视图(逻辑视图、开发视图、物理视图、过程视图、场景视图)以及实现 4+1 视图的主要攻击 UML(统一建模语言)。UML 视图中的部署图、组件图、组件时序图、用例图、状态图、活动图(类似流程图)、合作图、类图、对象图、包图等 10 种图。
这周讲了什么?
这周讲的是设计原则(开闭原则,里氏替换原则、依赖倒置原则、单一职责原则、接口隔离原则,迪米特原则(这个没说))
第一节:编程语言的历史(面向机器编程、面向劳动者编程、面向领域问题编程),面向对象语言能更好的映射现实世界的领域问题,更好的反应事物之间的交互规律。面向对象的目标:高内聚、低耦合(高内聚,低耦合的系统易于扩展、更强壮、可移植、更简单)。面向对象的 3 个重要特点:继承,封装,多态,其中多态是最核心的特点。基于这个目标的设计原则(六个设计原则)、设计模式(面向对象设计模式分 3 大类,共 23 种,其他并发编程有其他设计模式,设计模式是永久解决某一问题的通用解决方案),以及基于这些设计原则和设计模式构建出框架(框架是实现某一类应用的结构性程序,是对某一类框架方案可复用的设计与实现)。框架完成了真个系统骨干或程序运行的最基础的运行流程,关键构建了整个系统的整体结构。框架与工具的区别(框架调用应用程序,应用程序调用工具,框架保证架构落地,保证整体的程序运行流程和整体结构,工具提高开发效率)
第二节:软件设计的臭味:僵硬、脆弱、不可移植、导致无用的陷阱、晦涩、过渡设计(僵化性、脆弱性、牢固性、粘滞性、不必要的复杂性、不必要的重复性)。程序首先要先给人看,在给机器执行
第三节:开闭原则(OCP-Open/closed principle)对扩展是开发的,对更改是关闭的,不需要修改软件实体(类、函数、模块),就应该实现功能的扩展。实现开闭原则的关键在于抽象。软件工程的上下文是需求是在不断变化的,软件设计要能适应不断变化的需求。适配器模式、策略模式、观察者模式、装饰器模式都能很好的体现 开闭原则。
第四章:依赖倒置原则(DIP - Dependency Inversion Principle)高层模块不应该依赖低层模块,而是大家都依赖抽象,抽象不能依赖实现,而是实现依赖抽象。DIP 倒置了依赖的层次,改变了开发的先后顺序。DIP 是框架设计的指导原则,核心设计技巧。Don't call me, I'll call you.
第五节:里氏替换原则(LSP - Liskov Principle)子类必须能够替换掉他们的基类,LSP 是动态的看继承关系是否合理,在应用场景中看子类能不能替换父类,这样的分析更加坚定直接,也更符合继承的期望。静态的分析(is-a)未必是合理的。对象的核心特征在于其行为,LSP 从对象的行为上判断继承是否合理,更加合理。从契约角度看 LSP,从 Java 的语法看 LSP。解决不合理继承的两种方法:提取共性生成一个新父类和继承改为组合(减少不必要的继承,优先改为组合),继承的优点和缺点。可能违反 LSP 的征兆。里氏替换原则是一个关键继承的设计原则
第六节:单一职责原则(SRP - )又被称为“内聚性原则”,一个模块的组成元素直接的功能相关性,将它与引起一个模块改变的作用力相连。一个类(模块,函数),只能有一个引起它变化的原因。单一职责原则是类设计指导原则。什么是职责(一个职责是一个变化的原因),内聚性的原则,相同的功能聚合在一起,相同的职责聚合在一起,这个职责应该单一。违反 SRP 原则,程序会变得脆弱、不可移植。改进的方案是拆解类。接口隔离原则(ISP - Interface Segregation Principle)不应该强迫客户程序依赖他们不需要的方法。ISP 是接口设计的指导原则,ISP 和 SRP 的关系(都和内聚性相关),接口隔离实现手段时多继承。适配器在接口隔离中经常使用。胖接口的两种改进方法:适配器或多继承。《敏捷软件开发原则、模式与实践) 罗伯特森马丁:对于一个软件开发而言,要想实现敏捷的软件开发,并不在于敏捷的软件过程保证,当然过程保证也重要,重要的是在用设计本身是敏捷的。
第七节:反应式编程要解决的是线程被阻塞,导致的现在占据资源,不能释放资源,同时不能向下运行,导致系统资源耗尽,服务崩溃的问题。解决方法是**异步操作**。细细想来 Golang 也是解决这个问题的。go 的 csp 机制是 channle。Flower 的 csp 机制是 Actor(maibox)。go 中函数是一等公民,可以做函数式编程。flower 反应式编程框架的设计(通过接口限制住 service 的格式,应用开发中只要实现这些 service)和实现。
对设计原则的理解
软件开发的三要素:人、机器、领域问题。从编程语言的发展历史上看,初期是面向机器编程,这个时期的编程方式有:纸袋打孔、汇编语言。这个时期代码都是一个个指令,基本上谈不上内聚性。之后是面向人编程,这个时期的编程语言有:Basic 等语言,这些语言给开发带来了便利,但是系统规模的增大,导致了爆发了软件危机。《人月神话》这本书就是说的这个时期的事情。软件的低内聚带来了可复用、可维护,开发成本上的问题。现代的编程语言,面向对象编程,其实是面向领域问题编程。面向对象要解决的是系统的高内聚、低耦合问题。
面向对象更符合我们对问题的理解,也更符合我们对编程的认知。可以很方便的将现实世界的问题,映射成一个个对象。能更好的建立模型。编程的本质是通过层层的抽象,建立层层的映射,最终变成解决现实问题的系统。面向对象能更方便将领域问题的建成对象模型。也能更好的适应需求的变更。
面向对象语言目标是:高内聚、低耦合。它的 3 个特点是:继承、封装、多态。在这个的基础上提炼出了 6 个设计原则:开闭原则、里氏替换原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特原则。在 6 个设计原则的基础上,归纳出 23 种设计模式,设计模式分为:创建型、行为型、结构行三大类。另外对应不用的应用场景(领域)还有其他的设计模式(比如并发编程的模式)。
内聚和耦合是对立的。就行太极中的两个阴阳鱼,一阴一阳。阴盛则阳衰,阳盛则阴衰。内聚性高,则代码的复用性高,扩展性好,更强壮,容易阅读,可移植性好,重复代码少。相反耦合性高,则代码不易复用,扩展性差,容易出错,不易阅读,难以移植,重复代码多。内聚性高,相关代码聚合到一起,耦合性高,不相干代码聚到一起。内聚和耦合是功能相关性的指标。内聚和耦合是面向流程编程中,模块划分的指导思想。在面向对象中就变成了类设计的指导思想。
继承抽象出相关代码到父类,差异的代码在子类实现。这样提高了父类的内聚性。这样父类的代码可以复用,可以通过子类扩展不同的功能,子类更强壮。模板方法模式是继承的典型实例。
封装将可复用的功能提炼为一个类,隐藏类内部实现细节,通过一个供外部调用的方法(类间通过这个方法通信)。降低了对象间的耦合性,提高了内聚性。降低了改错代码的概率,代码也更容易扩展(只要供外部的方便不变),将错误封印在很小的范围内,适配器模式就是封装的典型实例。
多态是面向对象编程的一个重要的特点。有了多态,面向对象编程才表现出纷繁复杂的特点。各种编程技巧,都是围绕着多态展开的。多态的典型表现是重写和重载。子类重写父类方法,实现自己特有的逻辑,一组类可以实现一个接口。一个类内部可以重载多个同名方法,处理不同的业务逻辑。
通过多态内部结构不同的一组对象,可以享有相同的外部接口,通过一个公用类,它们可以用相同的方式调用。这样代码的扩展性大大的提高,可以做到在不修改原有功能的情况下,开发新的功能。同时代码也更强壮,更容易阅读,更简单,更容易阅读和维护,复用性也更好。策略模式、命令模式、观察者模式等是多态的典型实例。
里氏替换原则: 指导对象间继承关系设计。
依赖倒置原则:指导框架设计。
单一职责原则:指导对象的设计
接口隔离原则:指导接口的设计
开闭原则:在软件设计时,考虑到需求的不断变更,做到可以不修改的情况下天,实现需求变更。能做到开闭原则的设计,都是高内聚,低耦合的架构设计。
23 种设计模式体现的设计原则
待补充
软件框架设计的核心-依赖倒置原则
框架就是高层模块,框架定义自己的接口(也就是抽象,这些接口是高层模块定义的),根据抽象去设计和开发框架。使用框架去开发业务逻辑,这里就是低层模块,框架就可以根据接口去调用低层模块的应用程序。
依赖倒置原则,是框架设计的指导原则,是框架设计的核心技巧。它使架构师不纠结与程序设计的细节之中。架构师可以通过框架,框清代码,实现架构的落地
评论