写点什么

架构师训练营第 1 期第 2 周学习总结

用户头像
du tiezheng
关注
发布于: 2020 年 09 月 25 日

第2周 框架设计

 

1. 面向对象编程



编程语言的实质

1 在计算机所能理解的模型和现实世界之间建立一种联系。

2 将现实世界中的领域问题,分析抽象,生成一个模型,然后通过编程语言将这个模型实现。

3 模型一方面客观地反映了领域问题,跟客观世界的实体一一对应;另一方面,同软件实现中的对象也是一一对应的。

4 合理的抽取的模型,从而真实的反映客观需求,同时也反映如何开发系统。软件编程就变成用面向对象语言将抽象出来的模型模型实现的过程。



编程的核心要素

1 机器

汇编语言针对机器编程

2 人

面向过程语言针对人编程

3 业务领域

面向对象语言针对客观业务领域编程,面向数据编程本质上是面向对象编程的一个分支



把握了编程语言的核心要素,也就把握了编程语言的发展脉搏,未来出现新的语言,就可以准确判断新语言更细分了,还是倒退了。



面向对象编程要素

封装性 继承性 多态性



这些要素都不是面向对象编程语言独有的。

面向对象的各种编程技巧、设计模式、设计原则,都是围绕多态展开。掌握好多态,才能掌握好面向对象编程。面向对象编程,不是用面向对象语言进行编程,而是利用多态特性进行编程。



面向对象分析

面向对象分析是针对客观世界业务领域问题进行对象分析,指导对象设计。

贫血模型充血模型

领域驱动设计



面向对象设计目标

目标:高内聚、低耦合,使系统

易扩展--容易增加新功能

更强壮--不易被粗心程序员破坏

可移植--能够在多环境运行

更简单--易于理解、维护



面向对象的设计方法

如何实现高内聚,低耦合:

1 遵循设计原则

2 利用设计模式:遵循设计原则的模式

3 利用框架:基于设计原则设计模式开发的结构性程序

框架

1 实现某一类应用的结构性程序,对某一类架构方案的可复用设计实现。

2 简化开发者工作。

3 实现多种设计模式,使开发者不用很多精力就能设计出良好结构的程序。

4 框架 vs 工具:框架调用应用程序代码,应用程序代码调用工具

5 架构使用框架保证架构落地,用工具提升开发效率。



2. 代码的坏味道

僵化性:

很难对代码改动。单一改动会导致对依赖模块的连锁改动,要改动的模块越多,系统越僵化。

脆弱性:

对系统改动会导致与改动无关的其他地方出现问题。switch/case, if/else比抽象接口类更脆弱。

牢固性:

将部分代码从系统中分离成开重用组件,面临巨大风险。

粘滞性:

由于先前的错误改动方式,使得保持系统设计比破坏系统设计更难,做正确的事情比做错误的事情更困难。

复杂性:

设计中包含没有用的组成部分。当开发处理预测潜在变化,并在代码中放置处理潜在变化的代码,就会发生这种情况。

重复性:

设计中包含重复结构,而重复结构本身可通过单一抽象统一。编程时使用拷贝粘贴时,要留意这种情况发生。

晦涩性:

代码难以阅读、理解,随着时间推移,代码晦涩性会越来越强。



3. SOLID原则

从面向对象设计目标层面分类:

· OCP DIP LSP 更多关注低耦合

· SRP ISP 更多关注高内聚



·从面向对象特性层面分类:

· OCP、DIP针对多态,通过多态实现原则。

· LSP针对继承,限制继承的使用。

· SRP、ISP针对封装,指导类、接口本身的封装性设计。



开放封闭 OCP

对扩展开放,对修改封闭。不需要修改已存在的软件实体,就能实现功能的扩展。

如何实现:关键是抽象。定义抽象接口,使得接口本身和接口的调用保持不变,添加新功能时,对抽象接口进行扩展,从而实现开闭原则。



依赖倒置 DIP

高层不依赖于底层模块,而是大家都依赖于抽象(接口)。

抽象(接口)不依赖于实现,而是实现依赖于抽象。

低层模块实现一个接口,供高层模块调用不是依赖倒置;而高层模块定义一个接口,供低层模块实现,才是依赖倒置。这种倒置也倒置了开发者的依赖关系。

高层不依赖于低层模块,而是依赖于高层接口,使得高层更容易被复用。



DIP倒置了:

o 模块/包的依赖关系

o 开发顺序和职责



软件层次化:

o 高层决定低层

o 高层容易被复用



框架的核心:

o 框架不依赖于应用程序,应用程序依赖于框架(实现框架定义的接口)

o 好莱坞规则:Don't call me, I will call you.

o 倒转的层次依赖关系



里氏替换LSP

子类型必须能替换他的父类型,能不能替换,要放在场景中观察。

不符合IS-A关系的继承,一定不符合LSP

IS-A关系是关于行为的,设计界定一个类,应以其行为作为区分。



LSP要求,凡使用基类的地方,一定能使用其子类,因此:

o 子类一定拥有基类的整个接口。

o 子类的访问控制不能比基类更严格。

o 子类的契约不能比积累更严格。



如何重构代码解决LSP问题:

1. 提取共性到基类

2. 用组合替代继承



继承优缺点:

o 继承比较容易,大部分基类功能可通过继承进入子类。

o 继承破坏了封装,将基类功能暴漏给子类。

o 当基类发生变化,可能层层影响下面的子类

o 继承是静态的,无法运行时改变组合。

o 继承可能导致类数量爆炸。



优先使用组合替代继承。



检测LSP:

一个继承关系,如果孤立地看,不能判断继承意义的有效性,放在程序运行的调用上下文才能看出是否有问题。



可能违反LSP的征兆:

o 从基类到派生类出现退化函数。

o 派生类抛出异常,而基类本身不会抛出异常。



单一职责 SRP

一个类只能有一个因其他变化的原因,一个职责是指一个变化的原因。



违反SRP的后果:

脆弱性-- 将多个职责放在一起,修改其中一个,可能让另外一个意外受损。

不可移植性-- 外部应用本应只依赖一个功能,却被迫包含多个功能依赖。



在业务开发过程中,倾向于写一个大类,所有的方法都放在其中,通常当一个类太大时,类的职责就不单一了。当查看一个类需要频繁滚动屏幕,类可能就不单一了。

可以把一部分功能拆解分离到另一个类中,通过类的组合实现复杂功能。



有时区分一个类包含几个职责并不明显。

何时分离职责?当发生变化时。



常见的违反SRP原则的情形:

类中包含的两个职责,变化的原因不同,变化的快慢也不同。



接口隔离 ISP

不应该强迫用户依赖他们不需要的方法。



ISP与SRP关系:

o 都和'内聚性'有关。

o SRP关注类的内聚性,如何设计一个类。

o ISP关注接口的内聚性,从客户的角度出发,如何设计一个接口。

o IPS可作为SRP的补充,当类本身已足够内聚无法继续拆解,通过多继承分离多个接口,使得类使用者只依赖他所需要的类接口。



· 



用户头像

du tiezheng

关注

还未添加个人签名 2018.08.16 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第 1 期第 2 周学习总结