考查目标
1.课程目标 1
Ø 软件生命周期活动
可行性研究阶段、需求分析阶段、设计阶段、实现阶段(编码阶段)、测试阶段、运行与维护阶段
Ø 造成重构的主要原因
改进软件设计、使软件更容易理解、有助于查找错误
Ø 交互设计的基本原则
3条基本原则:
1.学习性。指的是新的用户能用它进行有效的交互并获得最大的性能。
2.灵活性。是指用户和系统能以多种方式交换信息。
3.健壮性。是指在决定成就和目标评估方面对用户提供的支持程度。
Ø 异常处理的模式
异常处理一般有两种模型:终止模式和恢复模式。
终止模式:假设错误非常关键, 导致程序无法返回到异常发生的地方继续执行。一旦抛出异常, 就表明错误已无法挽回, 也不能回来继续执行。
恢复模式:认为异常处理程序的工作是修正错误, 重新尝试调用出问题的方法, 并认为二次处理能成功。恢复模式希望处理异常后程序能继续执行。
try{
包含可能发生异常的语句
}
catch(Exception e){
处理异常的语句
}
finally{
类似分支语句中case的缺省情况default
}
Ø 瀑布式开发过程
瀑布式开发过程,也叫软件生存期模型。
按照软件生命周期,开发分为制定计划、需求分析、软件设计、程序编写、软件测试和运行维护等6 个基本活动。
各项活动严格按照线性方式进行,自上而下、相互衔接。每项活动的结果需要验证通过后,才能继续进行下一项活动。
Ø 模块化软件构造
模块化是把问题分解成容易理解、便于控制、便于实现的子问题的一个重要手段,是实现控制复杂性的方式。
模块化通过把一个程序分解成简单独立、互相作用的模块,对不同的模块设定不同的功能,来实现大型、复杂的程序。
模块是可组合、可更换的程序单元。良好设计的模块只完成一个特定的或一组相关的子功能。
所有模块按某种方法组装起来,成为一个整体,完成整个系统所要求的功能。
故事一
50 道100 以内的加减法口算习题。
循环50 次, 每次产生一个运算题: 随机地产生两个100 以内的整数, 随机地从两个运算符“ 加法” 和 “ 减法” 中挑选一个, 就可以生成一道口算题; 然后打印输出一套练习题。
//代码 2.1:一个 Java 程序,产生并逐行输出 50 道 100 以内的加减法算式package *cbsc.cha2;
*import java.util.Random;
public class BinaryOperation 0 {
public static void main(string[]args){
short m=0,n=0,ov=0;
char o='+';
Random random=new Random();
for(int i=0;i<50;i++){
ov=(short)random.nextInt(2);
m=(short)random.nextInt(101);
n=(short)random.nextInt(101);
if(ov==1){
o='+';
}else{
o='-';
}
System.out.println(""+(i+1)+":\t"+m+o+n+"=");
}
}
}
Ø 面向对象软件构造
“软件构造”指的是通过编码、验证、单元测试、集成测试和调试的组合,详细地创建可工作的、有意义的软件。
抽象与封装、面向对象设计
2.课程目标 2
Ø 测试层次
为了能系统、全面地测试软件,测试可以先从程序的基本单元开始,然后按照一定方式——如软件集成的顺序,逐步测试集成后的程序,直至测试完成整个软件。
按照软件的构成,测试可以划分为4 个阶段或层次:单元测试、集成测试、系统测试和验收测试。
(1)单元测试
对程序基本单元( 函数、方法、类或对象及构件或服务) 进行的测试。关注程序单元的基本功能、算法实现、数据结构等内部组织结构。
(2)集成测试
对两个及以上相互关联的程序单元测试。具有调用关系的函数、具有继承或聚合关系的类, 以及具有合作关系的子系统、软件使用或依赖独立的外部系统, 甚至是软硬件的交互。集成测试的重点是检测程序模块的接口、模块之间的交互及开发的软件与外部系统的交互。
(3)系统测试
对整个软件的测试称为系统( 级) 测试。重点是检测软件是否满足了用户需求、完成既定的功能和任务。同时, 还要检测运行速度、存储占用、事务处理、数据量及是否稳定、可靠、安全、易用、易维护等非 功能需求。
(4)验收测试
确保软件准备就绪, 最终用户可以在用户环境执行软件的既定功能和任务。验收测试是在产品发布之前进行的测试活动, 也称交付测试。
持续集成/持续测试(CI/CD)是一种技术,它允许开发人员在软件开发过程中自动执行测试,以快速发现和修复错误。在软件构造过程中,使用持续集成/持续测试可以帮助开发人员自动化地构建、测试和部署软件,从而提高开发效率
Ø 软件构造概念和重要性
“软件构造”指的是通过编码、验证、单元测试、集成测试和调试的组合,详细地创建可工作的、有意义的软件。
软件构造的重要性:提高代码质量、促进团队协作、降低维护成本等。
构造是软件开发的中心活动。
把重心放在构造, 能显著提升个体程序员的生产率。
构造的产品—— 源程序代码, 常常是唯一准确的软件描述。
构造是确保唯一要完成的活动。
Ø 基于软件构造的数据库设计
/代码 8.2:使用SQL代码创建Question关系时添加适当的完整性约束条件/
CREATE TABLE Question(
QuestionID VARCHAR(9) FOREIGN KEY,
Factorl INT CHECK(Factor1<=100),
Operator CHAR(2) CHECK(Operator IN (‘+’,‘-’,‘*’,‘/’)),
Factor2 INT CHECK(Factor2<=100),
Result INT CHECK(Result<=100),
CategoryID CHAR(9),
FOREIGN KEY (CategoryID) REFERENCES Category(CategoryID)
);
3.课程目标 3
Ø 快速原型法
快速原型是快速建立起来的可以在计算机上运行的程序,它所能完成的功能往往是最终产品能完成的功能的一个子集。
Ø 防御性编程
防御编程的基本思想是:程序员要预计其他程序员的过错、无效的输入、甚至有害的数据及使用者的过失,即使这种事情罕见,也要采取适当措施保护自己的程序。
保护程序无效输入破坏的基本原则:检查每个输入参数的数据;特别要检查从程序外部进入程序的数据。一旦发现了无效数据,就要决定处理的方式。基本的方式有处理错误和使用异常。
防御性编程数据错误出现时的一些建议:
1.继续运行程序、返回中性无害的数据。
2.用最接近的有效数据替换无效数据。
3.在日志中记录警告信息并继续运行程序。
4.调用错误处理程序或对象。
5.屏幕显示错误信息。
6.尽可能在局部处理错误。
7.返回一个错误编码,让特定程序处理这个错误。
处理错误的方式:使用异常
Ø 开发数据库应用程序
需求分析阶段;
概念结构设计阶段;
逻辑结构设计阶段;
物理结构设计阶段;
数据库实施阶段;
数据库运行和维护阶段。
4.课程目标 4
Ø ER 图
Ø 用例图
Ø 类图
Ø SQL 语句
创建:
CREATE TABLE 语句定义基本表。
CREATE TABLE <表名> (
<列名><数据类型>[ 列级完整性约束条件] [, <列名><数据类型>[ 列级完整性约束条件]]
…
[,<表级完整性约束条件>]
);
插入元组的INSERT语句:
INSERT插入语句的一般格式为:
INSERT INTO <表名>[( <属性列1 >, <属性列2 >,……)] VALUES( <常量1 >, <常量2 >,……);
插入如下题目:编号1001 的题目为19 + 20 = 39 ,题目属于基础的四则运算。
INSERT INTO Question VALUES(' 1004 ', 20 ,'-', 19 , 1 , 1 );
删除:
DELETE 语句的一般形式为:
DELETE FROM <表名> [ WHERE <条件>];
删除编号为1001 的题目:
DELETE FROM Question WHERE Question ID=’1001 ’;
删除所有的题目:
DELETE FROM Question;
更新:
UIPDATE 语句的一般形式为:
UPDATE<表名> SET <列名>=<表达式>[, <列名>=<表达式>]… [ WHERE<条件>];
如,修改Question 关系中编号1002 的题目运算结果为30 :
UPDATE Question SET Result= 30 WHER Question ID=' 1002 '
选择:
SELECT [ALL|DISTINCT] <目标列表达式>[,<目标列表达式>]…
FROM <表名或视图名> [,<表名或视图名>]…
[WHERE <条件表达式>]
[ORDER BY <列名> DESC | ASC]
[GROUP BY <列名> HAVING <条件表达式>];
Ø 代码重构
思考:软件构造在企业级项目中的应用
主要体现在以下几个方面:
抽象与封装:通过抽象和封装提高代码的可读性、可维护性和可重用性,应对企业级应用复杂的业务逻辑和数据结构。
依赖管理:使用依赖管理工具管理大量第三方库和模块,确保版本兼容性。
多线程与并发处理:利用Java的多线程特性或第三方库提高并发性和应用程序吞吐量。
测试与调试:通过彻底的测试和调试确保企业级应用的可靠性。
定制化解决方案:根据企业业务需求创建定制化软件,实现业务集成、数据安全和隐私保护等。
题库
1.工厂方法模式
- 描述工厂方法模式的应用场景,并绘制其UML类图。
使用场景:工厂方法模式的使用场景非常广泛,特别是在需要简化对象创建过程、提高代码扩展性和可维护性、以及实现动态对象创建等情况下,工厂方法模式都是一个非常有效的解决方案
工厂方法模式类图:
图例说明:
Factory(工厂角色):即工厂类,它是简单工厂模式的核心,负责实现创建所有实例的内部逻辑;在工厂类中提供了静态的工厂方法createProduct(),它返回一个抽象产品类Product,所有的具体产品都是抽象产品的子类。
Product(抽象产品角色):抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
其他的是具体产品类:每一个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法 。
2.多态性
4.请解释多态性的概念,并说明它在面向对象编程中的优势。
多态性是面向对象编程中的一个核心概念,指的是同一操作可以作用于不同的对象上,表现出不同的行为。多态性主要通过两种方式实现:
方法重载:在同一个类中,可以定义多个同名但参数列表不同的方法。调用时,根据传入参数的类型和数量来决定调用哪个具体的方法。
方法覆盖:子类可以重写父类的方法,实现特定的功能。在运行时,根据对象的实际类型来决定调用哪个版本的方法。
多态性的优势:
1、提高代码的可扩展性:多态性允许在不修改现有代码的情况下,添加新的类和方法。例如,可以通过继承和重写来扩展功能,使得系统能够方便地适应新的需求。
2、简化代码:通过使用接口或抽象类,可以定义统一的方法接口,使得不同的类可以以相同的方式被调用,从而简化了代码的复杂性,提高了可读性和维护性。
3、增强代码的灵活性:多态性允许程序在运行时决定调用哪个对象的方法,这种动态绑定使得程序能够根据实际情况灵活地选择具体的实现。
例如:在太阳系八大行星系统中,对八大行星进行方法覆盖来实现不同行星的不同轨道和公转周期。通过多态,不仅简化了代码,更提高了代码的可拓展性。
3.在线购物系统
1.有一个线购物系统,包含以下核心功能:
商品的管理(包括添加、删除、修改商品信息)。
用户的管理(包括注册、登录、个人信息管理)。
购物车功能,允许用户添加、删除、修改购物车中的商品。
订单管理,包括订单的创建、支付、取消和查询。
思考上述系统的功能和设计 ,完成以下三道设计题 :
(1)分析该系统中会有存在哪些类和页面
(2)采用MVC(Model-View-Controller)架构模式设计系统,并画出相应的架构图
(3)完成购物车的用例图
答案:
(1)该系统有商品类、用户类、订单类等,负责业务逻辑和数据处理;
还有各个业务层的控制类,如商品控制类等,负责接收用户的请求并做出相应的响应;
系统包含商品展示页面、用户登录页面、购物车页面、订单页面等,负责与用户交互。
(2)架构图如下:
Model层:包含商品类、用户类、订单类等,负责业务逻辑和数据处理。
View层:包含商品展示页面、用户登录页面、购物车页面、订单页面等,负责与用户交互。
Controller层:处理用户的请求,调用Model层的方法完成业务逻辑,并将结果返回给View层展示。
(3)购物车的用例图如下:
1.查看购物车:用户可以查看购物车中的商品列表,包括商品名称、数量、价格等信息。
2.向购物车中添加商品:用户可以从商品列表中选择商品并添加到购物车中。
3.从购物车中删除商品:用户可以从购物车中删除不需要的商品。
4.修改购物车中的商品数量:用户可以增加或减少购物车中某个商品的数量。
5.清空购物车:用户可以清空购物车中的所有商品。
6.结算购物车中的商品:用户可以选择购物车中的商品进行结算,进入订单确认和支付流程。
4.文件操作,防御性编程
3.在软件开发中,文件操作是一个常见的任务,但文件操作往往伴随着各种潜在的异常,如文件不存在、文件权限不足、读取过程中发生IO错误等。请编写一个防御性编程风格的Java方法,该方法用于安全地读取文件内容,并妥善处理可能发生的各种异常。(难)(6-2 防御性编程)
要求 :
方法签名:public String readFileContent(String filePath)
方法应实现以下功能:
(1)检查文件路径是否为空或null,如果是,则抛IllegalArgumentException。
尝试读取文件内容,并返回文件内容的字符串表示。
(2)捕获并处理以下异常:
FileNotFoundException:文件不存在时,记录日志并返回特定的错误信息"File not found: " + filePath。
SecurityException:没有文件读取权限时,记录日志并返回特定的错误信息:"No permission to read the file: " + filePath。
IOException:读取过程中发生IO错误时,记录日志并返回特定的错误信息:"IO error while reading the file: " + filePath。
使用try-with-resources语句确保文件资源被正确关闭。
记录异常信息时,可以使用System.err.println来模拟日志记录。
防御性编程代码如下:
import java.io.*;
public class FileReaderUtil {
public String readFileContent(String filePath) {
// 检查文件路径是否为空或null
if (filePath == null || filePath.isEmpty()) {
// 如果文件路径为空或者null则抛出异常
throw new IllegalArgumentException("File path cannot be null or empty");
}
// 尝试读取文件内容,并通过try,catch捕获并处理三种异常
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append(System.lineSeparator());
}
return content.toString();
} catch (FileNotFoundException e) {
// 文件不存在时,记录日志并返回特定的错误信息
System.err.println("File not found: " + filePath);
return "File not found: " + filePath;
} catch (SecurityException e) {
// 没有文件读取权限时,记录日志并返回特定的错误信息
System.err.println("No permission to read the file: " + filePath);
return "No permission to read the file: " + filePath;
} catch (IOException e) {
// 读取过程中发生IO错误时,记录日志并返回特定的错误信息
System.err.println("IO error while reading the file: " + filePath);
return "IO error while reading the file: " + filePath;
}
}
public static void main(String[] args) {
FileReaderUtil fileReader = new FileReaderUtil();
// 测试文件路径为空
try {
System.out.println(fileReader.readFileContent(""));
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
// 测试文件不存在
System.out.println(fileReader.readFileContent("non_existent_file.txt"));
// 测试文件权限不足,手动创建一个无法读取的文件进行测试
System.out.println(fileReader.readFileContent("/path/to/unreadable/file1.txt"));
// 测试正常读取,手动创建一个可正常读取的文件进行测试
System.out.println(fileReader.readFileContent("/path/to/readable/file2.txt"));
}
}
5. 订单处理系统,重构冗余逻辑
在软件开发过程中,随着功能的增加和修改,代码中可能会出现冗余的逻辑。这些冗余逻辑不仅增加了代码的复杂性,还可能导致维护困难、性能下降等问题。现在,你有一个简单的订单处理系统,其中包含了一些冗余的代码逻辑。你的任务是识别并重构这些冗余逻辑,使代码更加简洁、易读和可维护。
原始代码 :
public class OrderProcessor {
public double calculateTotal(Order order) {
double total = 0.0;
// 处理普通商品
for (OrderItem item : order.getItems()) {
if (item.getType().equals("regular")) {
total += item.getPrice() * item.getQuantity();
}
}
// 处理折扣商品(这里有一段冗余的逻辑)
for (OrderItem item : order.getItems()) {
if (item.getType().equals("discount")) {
total += item.getPrice() * item.getQuantity() * 0.8; // 假设折扣是20%
}
}
// 处理特殊商品(这里也有一段冗余的逻辑)
for (OrderItem item : order.getItems()) {
if (item.getType().equals("special")) {
// 假设特殊商品有额外的处理逻辑,比如价格计算方式不同
total += calculateSpecialItemPrice(item);
}
}
return total;
}
private double calculateSpecialItemPrice(OrderItem item) {
// 特殊商品的价格计算逻辑
return item.getPrice() * item.getQuantity() * 1.1; // 假设特殊商品有10%的加价
}
// ... 其他方法和类定义 ...
}
class Order {
private List items;
// ... 其他属性和方法 ...
}
class OrderItem {
private String type;
private double price;
private int quantity;
// ... 其他属性和方法 ...
}
重构要求 :
-
描述上述代码中冗余的部分,并给出重构思路
-
重构代码
重构后的代码如下:
import java.util.List;
public class OrderProcessor {
public double calculateTotal(Order order) {
double total = 0.0;
for (OrderItem item : order.getItems()) {
switch (item.getType()) {
// 处理普通商品
case "regular":
total += item.getPrice() * item.getQuantity();
break;
// 处理折扣商品
case "discount":
total += item.getPrice() * item.getQuantity() * 0.8; // 折扣20%
break;
// 处理特殊商品
case "special":
total += calculateSpecialItemPrice(item);
break;
default:
// 可以抛出异常或记录日志,表示遇到了未知的商品类型
throw new IllegalArgumentException("Unknown item type: " + item.getType());
}
}
return total;
}
private double calculateSpecialItemPrice(OrderItem item) {
// 特殊商品的价格计算逻辑
return item.getPrice() * item.getQuantity() * 1.1; // 特殊商品加价10%
}
// 其他方法和类定义...
}
// 这里Order和OrderItem类是不用重构的
class Order {
private List items;
// 其他属性和方法...
}
class OrderItem {
private String type;
private double price;
private int quantity;
// 其他属性和方法...
}
在重构代码的过程中,发现原始代码中有多次的for循环和if语句,过于冗余,采用switch语句来替代多个if语句可以消除冗余的循环。将处理商品类型的业务逻辑集中在一个循环内,提高了代码的可读性和可维护性,也加强了代码的可拓展性。如果未来需要添加心得商品类型,只需要在switch语句中添加对应的分支即可实现。
6.MVC 架构
MVC架构,即模型-视图-控制器(Model-View-Controller)架构,是一种软件工程中的软件架构模式。它将应用程序分为三个主要部分:模型(Model)、视图(View)和控制器(Controller),以实现代码的分层组织和关注点的分离。
MVC架构的基本概念:
模型(Model):负责处理应用程序的核心业务逻辑和数据管理。它与数据库进行交互,完成数据的增删改查等操作,并对数据进行封装和抽象。模型不关心数据的展示方式,只负责提供数据服务。在MVC架构中,可以有多个模型,每个模型负责不同的业务领域。
示例:在Java Web开发中,模型层可能包含Service类和DAO类。Service类负责处理业务逻辑,而DAO类负责与数据库进行交互。
视图(View):负责数据的展示和用户交互。它根据模型提供的数据,以用户友好的方式呈现给用户,并接收用户的输入。视图通常与模型直接关联,并响应用户的操作更新模型数据。视图可以是图形界面、命令行界面等,具体形式取决于应用程序的需求。
示例:在Web开发中,视图层可能包含HTML、JavaScript、CSS、JSP、jQuery等前端技术实现的页面。
控制器(Controller):负责接收用户的请求并做出相应的响应。控制器接收用户的输入,调用相应的模型进行处理,并将结果传递给视图进行展示。控制器充当了模型与视图之间的协调者,确保数据的正确流动和处理。控制器还负责处理业务逻辑和流程控制,以确保应用程序的正确运行。
示例:在Java Web开发中,控制器层可能包含使用Spring MVC框架实现的Controller类,这些类处理HTTP请求,并调用Service层的方法来处理业务逻辑。