架构师训练营第二周

用户头像
Melo
关注
发布于: 2020 年 06 月 11 日



详细设计有时候也是架构师完成的。

架构师要有破局的能力。



汇编语言:对机器编程。

高级语言:对人编程。

面向对象语言:对面对的问题编程。 对问题领域进行抽象。

  • 多态 核心特性 (子类实现父类活着接口的抽象方法,程序使用抽象父类或者接口编程,运行时期注入不同的子类,就有了多态)

  • 继承

  • 封装



http://www.uml.org.cn/appCase/200701244.asp



框架

框架是用来实现某一类应用的结构性程序,是对某一类架构方案可复用的设计与实现

  • 实现了多种设计模式,使应用开发者不需要花太大的力气,就能设计出结构良好的程序

  • 如同框架结构的大厦的框架



软件设计的目的,是达到强内聚,低耦合。



定义好了interface,使用者改变具体的reader/writer遵守interface定义。



软件原则:

原则1: Open/Closed Principle

  • 对于扩展是开放的

  • 对于更改是封闭的

  • 添加一个新的功能应该是,在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)。

  • 开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。

  • 同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”。比如,添加属性和方法相当于修改类,在类这个层面,这个代码改动可以被认定为“修改”;但这个代码改动并没有修改已有的属性和方法,在方法(及其属性)这一层面,它又可以被认定为“扩展”。实际上,我们也没必要纠结某个代码改动是“修改”还是“扩展”,更没必要太纠结它是否违反“开闭原则”。我们回到这条原则的设计初衷:只要它没有破坏原有的代码的正常运行,没有破坏原有的单元测试,我们就可以说,这是一个合格的代码改动。

  • 我们要时刻具备扩展意识、抽象意识、封装意识。在写代码的时候,我们要多花点时间思考一下,这段代码未来可能有哪些需求变更,如何设计代码结构,事先留好扩展点,以便在未来需求变更的时候,在不改动代码整体结构、做到最小代码改动的情况下,将新的代码灵活地插入到扩展点上。

  • 在识别出代码可变部分和不可变部分之后,我们要将可变部分封装起来,隔离变化,提供抽象化的不可变接口,给上层系统使用。

  • 在众多的设计原则、思想、模式中,最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比如,装饰、策略、模板、职责链、状态等)。



原则2: 依赖倒置原则(Dependency Inversion Principle)

  • 高层模块不能依赖低层模块,而大家都是依赖于抽象 (controller:高层模块;service:低层模块)

  • controller 定义一个接口,service需要去实现这个register接口,依赖就倒置了。重要的点是谁来定义接口

  • 抽象不能依赖实现,而是实现依赖抽象

  • 所谓高层模块和低层模块的划分,简单来说就是,在调用链上,调用者属于高层,被调用者属于低层。在平时的业务代码开发中,高层模块依赖底层模块是没有任何问题的。实际上,这条原则主要还是用来指导框架层面的设计。我们拿 Tomcat 这个 Servlet 容器作为例子来解释一下。Tomcat 是运行 Java Web 应用程序的容器。我们编写的 Web 应用程序代码只需要部署在 Tomcat 容器下,便可以被 Tomcat 容器调用执行。按照之前的划分原则,Tomcat 就是高层模块,我们编写的 Web 应用程序代码就是低层模块。Tomcat 和应用程序代码之间并没有直接的依赖关系,两者都依赖同一个“抽象”,也就是 Servlet 规范。Servlet 规范不依赖具体的 Tomcat 容器和应用程序的实现细节,而 Tomcat 容器和应用程序依赖 Servlet 规范。

  • 框架的核心: Don't call me, I'll call you. 框架定义接口。



原则3: 里氏替换原则

  • 子类对象(object of subtype/derived class)能够替换程序(program)中父类对象(object of base/parent class)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏。

  • 子类得拥有基类的所有接口

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

  • 子类的“契约“不能比父类更严格(Square长宽相等,比长方形更严格,所以正方形不是长方形的子类。

  • 子类在设计的时候,要遵守父类的行为约定(或者叫协议)。父类定义了函数的行为约定,那子类可以改变函数的内部实现逻辑,但不能改变函数原有的行为约定。这里的行为约定包括:函数声明要实现的功能对输入、输出、异常的约定甚至包括注释中所罗列的任何特殊说明。实际上,定义中父类和子类之间的关系,也可以替换成接口和实现类之间的关系。

  • 判断子类的设计实现是否违背里式替换原则,还有一个小窍门,那就是拿父类的单元测试去验证子类的代码。如果某些单元测试运行失败,就有可能说明,子类的设计实现没有完全地遵守父类的约定,子类有可能违背了里式替换原则。

违反的地方:加入新子类,就会有问题。 定义Shape接口,shape.draw()

基本不写if else.



解决方法:改成组合。



原则4:单一职责原则



原则5:接口隔离原则 Interface Segregation Principle



优秀总结链接:

https://xie.infoq.cn/article/f1e59835a2655e4996e1964b0

优秀作业链接:

https://xie.infoq.cn/article/f1e76ad26dafd6c7b0c671c49

https://xie.infoq.cn/article/989974492013ddc839503d44a



用户头像

Melo

关注

还未添加个人签名 2019.09.17 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第二周