正向建模与开发 以及 架构设计、比对
第一次作业
在第一次作业中,由于是从零开始搭建代码架构,所以需要事先思考代码的大致功能,以及代码间交互。此时,通过创建UML类图,初步描绘自己的设想,厘清各个可能需要的类的功能。
首先,目标是搭建一个简易的图书管理系统。图书馆一定有书本,因此创建类Book。根据题目要求中要求了书架(BookShelf)、借还处(Circulation)和预约处(Appointment)三个部门,因此我创建了对应的三个类。这三个类分别根据题目要求,确定了基本功能。再考虑功能,需要有请求,需要有人,所以再创建两个类Request、Person。
为了提高代码的模块化、标准化,在为方法分配功能时,尽量降低功能的复杂性,每个方法仅实现一个基础功能。为了实现各部门之间的交互,需要一个策略类来控制它们的交互,所以又建立了一个策略类,称为Library。
在创建完类,并添加完方法后,初步考虑其数据结构。
第二次作业
在第二次作业中,添加了漂流角,因此添加一个类DriftCorner。由于第一次作业中已经搭建了类图,所以添加时很方便,并且能快速弄清楚它应该能够与哪些类实现怎样的交互。
第二次作业要求创建书本的状态图。在做作业时,已有的代码中并没有能表示书本迁移动向的属性,因此,为了满足状态图的需求,在各个类中添加了所需属性,仅为了表示动向,没有什么实际用途。
第三次作业
加了个信誉分,没什么影响。
增加了UML顺序图,在构建时依据针对一项功能的实现中访问类的顺序。相对来说比状态图的构建简单。
架构设计思维的演进
第一单元
第一单元使用了递归下降的方法,将表达式分为表达式、项、因子三个层次。每次新增要求时,对每个层次进行功能上的拓展,这样能沿用之前的架构,对架构没有什么影响。
第二单元
第二单元使用了生产者-消费者模型。在控制器中接收指令,并将指令传递给策略类,策略类再分发给各个电梯轿厢。将电梯实现基本功能,具体功能的实现由这些基本功能组合实现。策略类与电梯的实现互不干涉。
第三单元
第三单元主要是算法,架构课程组已经设计好了。在完成作业时感受到课程组的架构非常简练,功能分工清晰。
第四单元
第四单元设计了几个容器。功能实现由一个控制类(即Library)控制这些容器进行交互来完成。每个容器提供一系列基本方法,与外界进行信息交互。相对来说,我在这个单元的架构设计最为清晰。
测试思维的演进
第一单元
- 构造极端数据:如0、INT_MAX
- 情况全覆盖:+1、-1、^+1等
- 复杂性测试:每次测试针对某一种情况,构造能嵌套这种情况的数据,以此实现对该方法在一次任务中的大量使用,以此来测试性能。
第二单元
- 大量数据进行压力测试
- 白盒测试:硬看代码
第三单元
- 模块化测试:在拥有约束的情况下,对每一个方法实现的正确性进行测试,这种方法最为高效、清晰
第四单元
结合模块化测试、情况全覆盖等
课程收获
对面向对象三大技术特征、设计的基本原则有了更深的理解。
封装(Encapsulation)
封装是隐藏对象的属性和实现细节,仅对外提供公共访问方式的过程。
通过封装,我们可以控制对对象属性的访问级别(public、private、protected),从而保护对象内部状态不被随意修改,并防止外部代码对对象内部细节的依赖。
封装有助于实现模块化和信息隐藏,使得代码更加安全、易于维护和扩展。
继承(Inheritance)
继承是一种类与类之间的关系,表示一个类(称为子类或派生类)可以继承另一个类(称为父类或基类)的属性和方法。
通过继承,子类可以重用父类的代码,并可以添加或覆盖父类的属性和方法,从而实现代码复用和扩展。
继承有助于构建层次结构清晰的类体系,使得代码更加模块化、易于管理和维护。
多态(Polymorphism)
多态是指不同对象对同一消息做出不同的响应。
在面向对象编程中,多态通常通过方法重写(Override)和接口实现(Implementation)来实现。
通过多态,我们可以编写更加灵活和可复用的代码,因为我们可以将不同的对象视为相同的类型(接口或基类),并调用它们的方法,而无需关心它们的具体实现。
开闭原则(Open-Closed Principle)
软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
这意味着我们应该通过添加新功能来扩展软件,而不是通过修改现有代码来实现。
单一职责原则(Single Responsibility Principle)
一个类应该只有一个引起变化的原因。
这意味着我们应该将类的功能划分得尽可能小,使得每个类只负责一个特定的功能或一组紧密相关的功能。
里氏替换原则(Liskov Substitution Principle)
子类必须能够替换其父类,并且替换后不会影响程序的正确性。
这意味着子类应该遵循与父类相同的契约(接口和约定),以确保它们可以在任何地方被父类所替代。
依赖倒置原则(Dependency Inversion Principle)
高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
这意味着我们应该将代码设计为依赖于接口或抽象类,而不是具体的实现类,以减少代码之间的耦合度。
接口隔离原则(Interface Segregation Principle)
客户端不应该依赖它不需要的接口。
这意味着我们应该将接口拆分为更小的、更具体的接口,以便客户端只需要知道和使用它们所关心的部分。
迪米特法则(Law of Demeter)
一个软件实体应当尽可能少地与其他实体发生相互作用。
这意味着我们应该尽量减少对象之间的依赖关系,降低系统的复杂性和耦合度。
通过对这些概念和原则的深入理解,我们可以编写出更加健壮、可维护、可扩展和可复用的面向对象代码。