01-概述-UML

  • 如果你的代码以某种莫名奇妙方式跑起来,就不要再碰它了!!!

1. 代码质量好坏

  • 评价代码的质量,有以下几个常用标准:
image-20240423102320690

1. 可维护性

  • Maintainability
  • 可维护性强的代码:在不去破坏原有的代码设计以及不引入新的BUG的前提下,能够快速的修改或者新增代码
  • 不易维护的代码:在添加、修改一些功能逻辑时,存在极大的引入新BUG的风险,并且需要花费很长时间

代码可维护性的评判标准比较模糊。因为针对维护的人员来说的不同水平的人对于同一份代码的维护能力是不同的。所谓 ”难者不会,会者不难“

2. 可读性

  • 软件开发教父,Martin Fowler曾经说过一句话: "任何傻瓜都能够编写计算机能理解的代码,而优秀的程序员能够编写人类能理解的代码。"
  • 代码的可读性会在很大程度上影响代码的可维护行性

code review(代码审查,一种测试代码可读性的手段)

  1. 检查代码风格、编程规范:代码是否符合编码规范、命名是否达意、注释是否详尽、模块划分是否清晰等
  2. 检查常规的 bad smell 和代码 bug:是否存在重复代码、过长函数、过大类、过于亲密的两个classes等

3. 可扩展性

  • Extensibility / Scalability
  • 不修改或少量修改原有代码的情况下,通过扩展的方式添加新功能代码

可扩展性的背后其实就是:"对修改关闭,对扩展开放" 设计原则

4. 灵活性

  • flexibility / mobility / adaptability
  • "灵活" 是指在添加新代码的时候,已有代码能够不受影响,不产生冲突,不出现排斥,在保证自身不遭到破坏的前提下灵活地接纳新代码

下面的几个场景,可以体现代码的灵活性

  1. 添加新功能代码,原有代码已经预留了扩展点,不需要修改,直接在扩展点上新增代码即可
  2. 实现一个功能模块时,发现原有代码中,已经抽象出了很多底层可以复用的模块、类等代码,可以直接拿来使用
  3. 使用某组接口时,这组接口可以应对各种使用场景,满足不同需求,接口设计十分灵活易用

5. 简洁性

  • 要遵从KISS(Keep It Simple Stupid)原则,代码要尽可能的简单;但是思从深而行从简,真正的高手能云淡风轻地用最简单的方法解决最复杂的问题。这也是一个编程老手跟编程新手的本质区别之一

代码的写法应当使别人理解它所需的时间最小化

6. 可复用性

  • Reooxx
  • 尽量减少重复代码的编写,复用已有的代码
  • 可复用性也是一个非常重要的代码评价标准,是很多设计原则、思想、模式等所要达到的最终效果
  • 可复用性与DRY(Don't Repeat Yourself)避免编写重复的代码逻辑. 原则关系紧密

7. 可测试性

  • 单元测试在一个完整的软件开发流程中是必不可少的、非常重要的一个环节。通常写单元测试并不难,但有时候,有的代码和功能难以测试,导致写起测试来困难重重。所以写出的代码具有可测试性,具有很重要的作用

代码可测试性的好坏,能从侧面上非常准确地反应代码质量的好坏

2. 编程方法论

  • 面向对象思想 (基础)
  • 设计原则 (指导方针)
  • 设计模式 (设计原则的具体实现)
  • 编程规范 (提高代码可读性)
  • 重构 (面向对象设计思想、设计原则、设计模式、编码规范的融合贯通)
image-20220530160637842
  • 设计原则是高手的内功,设计模式是少林、武当、峨眉派的武术套路,编程规范是招式出拳、横扫,重构是组合拳融汇贯通各种组合,而想练好这些武功还要有扎实的基本功面向对象
  • 不要一味的去追求最新的技术(并不是说这样做不好,千万不要本末倒置),而忘记了一个程序员最重要的能力,是写出高质量的代码

1. 面向对象

  • 面向对象是一种编程思想,也是一种编程范式。现在大部分项目都是基于面向对象编程风格进行开发

2. 设计原则(重点)

  • 设计原则是指导代码设计的一些经验总结。在软件开发中,为了提高软件系统的可维护性、可复用性、可扩展性、灵活性,程序员要尽量根据设计原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本

  • 单一职责原则
  • 开闭原则
  • 里氏代换原则
  • 依赖倒转原则
  • 接口隔离原则
  • 迪米特法则

特点就是比较抽象,不需要死记硬背。根据自己所积累的经验和所处的业务场景,灵活运用这些原则

3. 设计模式(重点)

  • 针对软件开发中经常遇到的一些设计问题,总结出来的一套解决方案或者设计思路。大部分设计模式解决的都是代码的可扩展性
  • 设计模式是遵循设计原则的,设计模式相对于设计原则来说,没有那么抽象,而且大部分都不难理解,代码实现也并不复杂
  • 难点是了解它们都能解决哪些问题,掌握典型的应用场景,并且懂得不过度应用

4. 编程规范

  • 主要解决的是代码的可读性问题。编码规范相对于设计原则、设计模式,更加具体、更加偏重代码细节
  • 对于编码规范,考虑到很多书籍已经讲得很好了
  • eg:《编写可读性代码的艺术》《代码大全》《代码整洁之道》等。每条编码规范都非常简单、非常明确,偏向于记忆

5. 重构

  • 维基百科:在软件工程学里,重构通常是指在不改变代码的外部行为情况下而修改源代码,有时非正式地称为“清理干净”
  • 在极限编程或其他敏捷方法学中,重构常常是软件开发循环的一部分:开发者轮流增加新的测试和功能,并重构代码来增进内部的清晰性和一致性

在软件开发中,只要软件在不停地迭代,就没有一劳永逸的设计。随着需求的变化,代码的不停堆砌,原有的设计必定会存在这样那样的问题。针对这些问题,就需要进行代码重构。重构是软件开发中非常重要的一个环节。持续重构是保持代码质量不下降的有效手段, 能有效避免代码腐化到无可救药的地步

3. 设计模式

  • 设计模式到底在编程过程中起到了怎样的作用,在编程世界中它处在一个什么样的位置,它到底是一种抽象的设计思想,还是一套具体的落地方案
image-20220530160637842

1. 概述

在GOF编写的设计模式《可复用面向对象软件的基础》一书中说道:本书涉及的设计模式并不描述新的或未经证实的设计,我们只收录那些在不同系统中多次使用过的成功设计

  • 设计模式(Design pattern) 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
  • ”世上本没有路,走的人多了,变成了路“。在程序员的世界中,本没有设计模式,写代码是人多了,便总结出了一套能提高开发和维护效率的套路,即设计模式
  • 大部分设计模式要解决的都是代码的可重用性、可扩展性问题
  • 数据结构、算法是教你如何写出高效代码
  • 设计模式是如何写出可扩展、可读、可维护的高质量代码,所以跟平时的编码会有直接的关系,直接影响开发能力

2. 好处

  1. 从容应对面试中的设计模式相关问题
  2. 不再编写 bullshit-code
    • 类设计不合理,代码结构混乱,分层不清晰等代码问题
  3. 提高复杂代码的设计和开发能力
  4. 有助于读懂源码,学习框架事半功倍

3. 产生背景

  • 最初并不是出现在软件设计中,而是被用于建筑领域的设计中
  • 1977年美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫·亚历山大(Christopher Alexander),在他的著作《建筑模式语言:城镇、建筑、构造》中描述了一些常见的建筑设计问题,并提出了 253 种关于对城镇、邻里、住宅、花园和房间等进行设计的基本模式
image-20220113152017462

1990年软件工程界开始研讨设计模式的话题,后来召开了多次关于设计模式的研讨会

  • 在之前设计模式的绝大部分以往并无文本记录,它们或是来源于面向对象设计者圈子里的非正式交流,或是来源于某些成功的面向对象系统的某些部分,但对设计新手来说,这些东西是很难学得到的
  • 尽管这些设计不包括新的思路,但我们用一种新的、便于理解的方式将其展现给读者,即:具有统一格式的、已分类编目的若干组设计模式
  • 1994年,艾瑞克·伽马(ErichGamma)、理査德·海尔姆(Richard Helm)、拉尔夫·约翰森(Ralph Johnson)、约翰·威利斯迪斯(John Vlissides)等4位作者合作出版了《设计模式:可复用面向对象软件的基础》一书,在此书中收录了23个设计模式,这是设计模式领域里程碑的事件,导致了软件设计模式的突破
  • 备注:由于书名太长,人们将其简称为 "四人组(Gang of Four, GoF)的书", 并且很快进一步简化为 "GoF 的书"
  • 四人帮(GOF)
image-20220113150108444

4. 分类

  • GoF设计模式只有23个,但是它们各具特色 ,每个模式都为某一个可重复的设计问题提供了一套解决方案

1. 创建型模式(5种)

  • 提供创建对象的机制,提升已有代码的灵活性和可复用性
    • 常用:单例模式、工厂模式(工厂方法、抽象工厂)、建造者模式
    • 不常用:原型模式
image-20220530160637842

2. 结构型模式(7种)

  • 如何将对象、类组装成较大的结构,并同时保持结构的灵活、高效
    • 常用:代理模式、桥接模式、装饰者模式、适配器模式
    • 不常用:门面模式、组合模式、享元模式
image-20220530160637842

3. 行为模式(11种)

  • 负责对象间的高效沟通、职责传递委派
    • 常用:观察者模式、模板模式、策略模式、职责链模式、迭代器模式、状态模式
    • 不常用:访问者模式、备忘录模式、命令模式、解释器模式、中介模式
image-20220530160637842

2. UML类图

  • 统一建模语言(Unified Modeling Language,UML)用来设计软件的可视化建模语言
    • 特点:简单、统一、图形化、能表达软件设计中的动态与静态信息
    • UML从目标系统的不同角度出发,定义了用例图、类图、对象图、状态图、活动图、时序图、协作图、构件图、部署图等9种图

研究一个设计模式时,是需要借助UML类图更加准确的描述所使用的设计模式,和设计模式下类与类之间的关系

1. 概述

  • 类图(Class diagram)是显示了模型的静态结构,特别是模型中存在的类、类的内部结构以及与其他类的关系等。类图不显示暂时性的信息。类图是面向对象建模的主要组成部分

2. 作用

  • 在软件工程中,类图是一种静态的结构图,描述了系统的类的集合,类的属性和类之间的关系,简化人们对系统的理解
  • 类图是系统分析、设计阶段的重要产物,是系统编码和测试的重要模型

3. 表示法

  • UML类图中具体类、抽象类、接口、包有不同的表示方法

1. 具体类

  • 具体类用矩形框表示,矩形框分为三层:
    1. 第一层是类名
    2. 第二层是类的成员变量
    3. 第三层是类的方法
  • 成员变量以及方法前的访问修饰符用符号来表示
    • “+” 表示 public
    • “-” 表示 private
    • “#” 表示 protected
    • 不带符号表示 default
image-20220530160637842

2. 抽象类

  • 抽象类同样用矩形框表示,但是抽象类的类名以及抽象方法的名字用斜体字表示
image-20220530160637842

3. 接口

  • 接口用矩形框表示,第一层顶端用构造型<<interface>>表示,下面是接口的名字
image-20220530160637842

此外,接口还有另一种表示法,俗称棒棒糖表示法,就是类上面的一根棒棒糖(圆圈+实线)。圆圈旁为接口名称,接口方法在实现类中出现

4. 表示关系

  • 类和类、类和接口、接口和接口之间存在一定关系,UML类图中一般会有连线指明它们之间的关系
    • 实现关系
    • 泛化关系
    • 依赖关系
    • 组合关系(组合关系 + 关联关系 + 聚合关系)
  • 没有必要区分组合、聚合这两个概念。记住一点:多用组合少用继承
image-20220530160637842

1. 实现关系

  • 接口、实现类之间的关系
  • 使用带空心三角箭头的虚线来表示,箭头从实现类指向接口

eg:汽车、船实现了交通工具,其类图:

image-20220530160637842

2. 泛化关系

  • 面向对象的继承机制。对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系
  • 带空心三角箭头的实线来表示,箭头从子类指向父类

eg:Student类和Teacher类都是Person类的子类

image-20220530160637842

3. 关联关系

  • 关联关系是对象之间的一种引用关系。表示一类对象与另一类对象之间的联系
    • eg:老师和学生、师傅和徒弟、丈夫和妻子等
  • 是类与类之间最常用的一种关系,分为一般关联关系、聚合关系、组合关系
1. 一般关联关系
1. 单向关联
  • 用一个带箭头的实线表示
image-20220530160637842
2. 双向关联
  • 所谓的双向关联就是双方各自持有对方类型的成员变量
  • 一个不带箭头的直线表示
image-20220530160637842
3. 自关联
  • 一个带有箭头且指向自身的线表示
image-20220530160637842
2. 聚合关系
  • 一种弱的"拥有"关系,体现的是A对象可以包含B对象,但是B对象不是A对象的一部分

代码中:A类对象包含B类对象,B类对象的生命周期可以不依赖A类对象的生命周期,即单独销毁A类对象而不影响B对象

public class A {

	private B b;

	public A(B b) {
		this.b = b;
	}
}


 





  • 带空心菱形的实线来表示,菱形指向整体
image-20220530160637842
3. 组合关系
  • 是一种强"拥有"关系,体现了严格的部分和整体的关系,部分和整体的声明周期一样

代码中:A类对象包含B类对象,B类对象的生命周期依赖A类对象的生命周期,B类对象不可以单独存在

public class A {

    private B b;

    public A() {
        this.b = new B();
    }
}


 





  • 带实心菱形的实线来表示,菱形指向整体
image-20220530160637842

4. 依赖关系

  • 是一种使用关系,对象间耦合度最弱的一种关联方式,临时性的关联

代码中,某个类的方法通过局部变量、方法参数、对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责

  • 使用带箭头的虚线来表示,箭头从使用类指向被依赖的类
image-20220530160637842