实验二 Java面向对象程序设计
北京电子科技学院(BESTI)
实 验 报 告
课程:Java 班级: 1352 姓名:姬梦馨 学号:20135218
成绩: 指导教师:娄嘉鹏 实验日期:2015.5.8
实验密级: 预习程度: 实验时间:15:30~18:00
仪器组次:18 必修/选修:选修 实验序号:02
实验名称: Java面向对象程序设计
实验目的与要求:
1. 初步掌握单元测试和TDD
2. 理解并掌握面向对象三要素:封装、继承、多态
3. 初步掌握UML建模
4. 熟悉S.O.L.I.D原则
5. 了解设计模式
实验仪器:
名称 |
型号 |
数量 |
计算机 |
Dell |
1 |
统计的PSP(Personal Software Process)时间
步骤 |
耗时(min) |
百分比 |
需求分析 |
15 |
7.5% |
设计 |
40 |
20% |
代码实现 |
45 |
22.50% |
测试 |
40 |
20% |
分析总结 |
60 |
30% |
实验内容一:
(一)单元测试
(1) 三种代码
编程前要把干什么、如何干想清楚才能把程序写对、写好。想用程序解决问题时,要会写三种码:
- 伪代码
- 产品代码
- 测试代码
现在,我们通过一个例子说明如何写这三种代码。
需求:我们要在一个MyUtil类中解决一个百分制成绩转成“优、良、中、及格、不及格”五级制成绩的功能。
伪代码:
如果成绩小于60,不及格
如果成绩在60~70,及格
如果成绩在70~80,中等
如果成绩在80~90,良好
如果成绩在90~100,优秀
产品代码:
用java将伪代码翻译一下
测试代码:
用于测试产品代码。
尝试了50这个数字
但是50是显然不够的,下边多测试几组数据。
再测试一下-10和115这种错误数据,发现运行-10的结果不对,进行修改,测试通过。
测试一下边界数据:
发现100不对,进行修改代码,测试通过。
(2)TDD(Test Driven Devlopment, 测试驱动开发)
先写测试代码,然后再写产品代码的开发方法叫“测试驱动开发”(TDD)。
TDD的一般步骤如下:
- 明确当前要完成的功能,记录成一个测试列表
- 快速完成编写针对此功能的测试用例
- 测试代码编译不通过(没产品代码呢)
- 编写产品代码
- 测试通过
- 对代码进行重构,并保证测试通过(重构下次实验练习)
- 循环完成所有功能的开发
基于TDD,我们不会出现过度设计的情况,需求通过测试用例表达出来了,我们的产品代码只要让测试通过就可以了。
依然以上述例子为例:
我们增加第一个测试用例,测试用例方法名任意,输入以下代码:
此时代码存在语法错误,原因很简单,MyUtil
类还不存在,类中的percentage2fivegrade方法也不存在,我们在TDDDemo
的src
目录中新建一个MyUnil
的类,并实现percentage2fivegrade方法,如下图所示:
点击右键,进行运行调试
测试结果出现了一个红条(red bar),说明测试没通过,输入以下代码,进行调试成功。
增加一个测试异常情况,运行调试成功。
(二)面向对象三要素
(1)抽象
抽象就是抽出事物的本质特征而暂时不考虑他们的细节。对于复杂系统问题人们借助分层次抽象的方法进行问题求解;在抽象的最高层,可以使用问题环境的语言,以概括的方式叙述问题的解。在抽象的较低层,则采用过程化的方式进行描述。在描述问题解时,使用面向问题和面向实现的术语。 程序设计中,抽象包括两个方面,一是过程抽象,二是数据抽象。
(2)封装、继承与多态(三要素)
封装实际上使用方法(method)将类的数据隐藏起来,控制用户对类的修改和访问数据的程度,从而带来模块化(Modularity)和信息隐藏(Information hiding)的好处;接口(interface)是封装的准确描述手段。
以封装为基础,继承可以实现代码复用,需要注意的是,继承更重要的作用是实现多态。
多态是指不同的类对象调用同一个签名的成员方法时将执行不同代码的现象。多态是面向对象程序设计的灵活性和可扩展性的基础。
(三)设计模式初步
面向对象三要素是“封装、继承、多态”,任何面向对象编程语言都会在语法上支持这三要素。如何借助抽象思维用好三要素特别是多态还是非常困难的,S.O.L.I.D类设计原则是一个很好的指导:
- SRP(Single Responsibility Principle,单一职责原则)
- OCP(Open-Closed Principle,开放-封闭原则)
- LSP(Liskov Substitusion Principle,Liskov替换原则)
- ISP(Interface Segregation Principle,接口分离原则)
- DIP(Dependency Inversion Principle,依赖倒置原则)
OCP是OOD中最重要的一个原则,OCP的内容是
- software entities (class, modules, function, etc.) should open for extension,but closed for modification.
-
- 软件实体(类,模块,函数等)应该对扩充开放,对修改封闭。
- SRP的内容是:
- There should never be more than one reason for a class to change
- 决不要有一个以上的理由修改一个类
- LSP的内容是:
- Subtypes must be substitutable for their base types
- Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it
- 子类必须可以被其基类所代
- 使用指向基类的指针或引用的函数,必须能够在不知道具体派生类对象类型的情况下使用它
DIP的内容是:
- High level modules should not depend upon low level modules. Both should depend upon abstractions
- Abstractions should not depend upon details. Details should depend upon abstractions
高层模块不应该依赖于低层模块。二者都应该依赖于抽象
(四)练习 -
1)复数类ComplexNumber的属性 realPart: 实部,代表复数的实数部分 imaginPart: 虚部,代表复数的虚数部分 2)复数类ComplexNumber的方法 ComplexNumber() 构造函数,将实部,虚部都置为0 ComplexNumber(double r, double i) 构造函数,创建复数对象的同时完成复数的实部,虚部的初始化 getRealPart() 获取实部 getImaginaryPart() 获取虚部 getRealPart(double d) 设置实部 getImaginaryPart(double d) 设置虚部 add(ComplexNumber c) 复数相加 add(double c) 复数相加 minus(ComplexNumber c) 复数相减 minus(double c) 复数相减 ComplexMulti(ComplexNumber c) 复数相乘 ComplexMulti(double c) 复数相乘 toString() 把当前复数对象的实部,虚部组合成a+bi的字符串形式
-
伪代码:
首先设计一个复数类complex,定义三个构造方法:
①没有参数时默认为实部和虚部都为0;
②一个参数时默认为实数,即虚部为0,
③两个参数时分别为实部和虚部
再定义两个成员方法计算两个复数的和与差.定义一个print()方法输出复数的值,当虚部为0时不输出虚部. 最后定义一个song类使用complex类,在这个类的主方法中创建两个复数对象,分别计算这两个复数的和与差并输出.
-
产品代码:
public class Complex {
private int sh,xu;
Complex(){
this.sh=0;
this.xu=0;
}
Complex(int sh){
this.sh=sh;
this.xu=0;
}
Complex(int sh,int xu){
this.sh=sh;
this.xu=xu;
}
public void addFu(Complex p1,Complex p2){
System.out.println("这两个复数的和为:");
this.sh=p1.sh+p2.sh;
this.xu=p1.xu+p2.xu;
print();
}
public void minusFu(Complex p1,Complex p2){
System.out.println("这两个复数的差为:");
this.sh=p1.sh-p2.sh;
this.xu=p1.xu-p2.xu;
print();
}
public void outputFu(){
System.out.println("复数的值为:");
print();
}
public void print(){
if(this.xu>0){
System.out.println(this.sh+"+"+this.xu+"i");
}else if(this.xu<0){
System.out.println(this.sh+""+this.xu+"i");
}else{
System.out.println(this.sh);
}
}
}
(3)测试代码
二:总结单元测试的好处:
在单元测试活动中,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试,可以查找错误、写出高质量的代码、提高编程水平。
它还可以使代码可以放心修改和重构、使程序员从调用者而不是实现者的角度设计软件模块、使程序员将软件模块写得易于测试和调用,
从而有利于解耦、测试本身可作为被测代码的用法说明,从而替代了一部分文档功能。
三、遇到的问题及解决方法
定义源文件中的Junit测试用例,电脑老是提示java4必须有java5.。。解决方法:将进行百度,和反复尝试。
四、实验收获
本次实验让我了解到Java代码不是像我们想象的那么简单,为了代码的一次性的方便准确,我们应该写出三种代码:伪代码、产品代码、测试代码,这样的程序才更加方便使用。
运用好单元测试对以后自己的java编程很有好处,应加以熟悉和掌握。