实验二《Java面向对象程序设计》实验报告
实验内容
- 初步掌握单元测试和TDD
- 理解并掌握面向对象三要素:封装、继承、多态
- 初步掌握UML建模
- 熟悉S.O.L.I.D原则
- 了解设计模式
实验要求
- 没有Linux基础的同学建议先学习《Linux基础入门(新版)》《Vim编辑器》 课程
- 完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导
- 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。
- 请大家先在实验楼中的~/Code目录中用自己的学号建立一个目录,代码和UML图要放到这个目录中,截图中没有学号的会要求重做,然后跟着下面的步骤练习。
实验步骤
(一)单元测试
(1)三种代码
- 伪代码:拿到一个问题,不要直接动手编程序。要先构思框架——也就是我们所说的写伪代码,把解决问题的步骤用我们平时的语言写出来。
- 产品代码:真正用来实现产品的代码,把构思出来的伪代码用编程语言实现。
- 测试代码:测试自己的产品代码是否有漏洞,并根据漏洞修改、调整产品代码。
- 实验步骤:
- 新建
主类名+Test.class
:点击主类名——>Ctrl+Enter
——>Creat Test - 新建test文件夹:右键项目名——>New——>Directory
- 配置JUnit:Fire——>Project Structure——>Modules——>Dependencies——>绿色加号选第一个——>选中如图所示两个文件,一路OK选中就能配置好啦~
- 运行结果截图
(2)TDD(Test Driven Devlopment, 测试驱动开发)
- TDD的一般步骤如下:
- 明确当前要完成的功能,记录成一个测试列表
- 快速完成编写针对此功能的测试用例
- 编写产品代码
- 测试通过
- 对代码进行重构,并保证测试通过(重构下次实验练习)
- 循环完成所有功能的开发
- TDD的编码节奏
- 增加测试代码,JUnit出现红条
- 修改产品代码
- JUnit出现绿条,任务完成
- 实验步骤:先编写测试代码,再根据伪代码和测试代码编写产品代码。并在IDEA中使用Junit进行单元测试,出现绿条则测试通过
- 运行结果截图
(二)面向对象三要素
- 抽象
抽象就是抽出事物的本质特征而暂时不考虑他们的细节。对于复杂系统问题人们借助分层次抽象的方法进行问题求解;在抽象的最高层,可以使用问题环境的语言,以概括的方式叙述问题的解。在抽象的较低层,则采用过程化的方式进行描述。在描述问题解时,使用面向问题和面向实现的术语。程序设计中,抽象包括两个方面,一是过程抽象,二是数据抽象 - 封装、继承与多态
面向对象(Object-Oriented)的三要素包括:封装、继承、多态。
面向对象的思想涉及到软件开发的各个方面,如面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程实现(OOP)。 - 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,依赖倒置原则)
- 实验题目:对MyDoc类进行扩充,让其支持Float类
- 实验代码:
import java.util.Objects;
abstract class Data {
abstract public void DisplayValue();
}
class Integer extends Data {
int value;
Integer() {
value=100;
}
public void DisplayValue(){
System.out.println (value);
}
}
class Long extends Data {
long value;
Long() {
value=2147483647;
}
public void DisplayValue(){
System.out.println (value);
}
}
class Float extends Data {
float value;
Float() {
value=(float)20165322.0;
}
public void DisplayValue(){
System.out.println (value);
}
}
// Pattern Classes
abstract class Factory {
abstract public Data CreateDataObject();
}
class IntFactory extends Factory {
public Data CreateDataObject(){
return new Integer();
}
}
class LongFactory extends Factory {
public Data CreateDataObject(){
return new Long();
}
}
class FloatFactory extends Factory {
public Data CreateDataObject(){
return new Float();
}
}
//Client classes
class Document {
Data data;
Document(Factory factory){
data = factory.CreateDataObject();
}
public void DisplayData(){
data.DisplayValue();
}
}
public class MyDoc {
static Document d;
MyDoc(Document d) {
this.d = d;
}
public static void main(String[] args) {
d = new Document(new FloatFactory());
d.DisplayData();
}
}
- 运行结果截图:
(三)使用TDD的方式设计关实现复数类Complex
- 产品代码:
public class Complex {
// 定义属性并生成getter,setter
double RealPart;
double ImagePart;
// 定义构造函数
public Complex(){
RealPart = 0;
ImagePart = 1;
}
public Complex(double R,double I){
ImagePart = I;
RealPart = R;
}
//Override Object
public boolean equals(Object obj){
if(this == obj) {
return true;
}
if(!(obj instanceof Complex)) {
return false;
}
Complex complex = (Complex) obj;
if(complex.RealPart != ((Complex) obj).RealPart) {
return false;
}
if(complex.ImagePart != ((Complex) obj).ImagePart) {
return false;
}
return true;
}
public String toString() {
String string = "";
if (ImagePart > 0)
string = RealPart + "+" + ImagePart + "i";
if (ImagePart == 0)
string = RealPart + "";
if (ImagePart < 0)
string = RealPart + " " + ImagePart + "i";
return string;
}
// 定义公有方法:加减乘除
Complex ComplexAdd(Complex a) {
return new Complex(RealPart+a.RealPart,ImagePart+a.ImagePart);
}
Complex ComplexSub(Complex a) {
return new Complex(RealPart-a.RealPart,ImagePart-a.ImagePart);
}
Complex ComplexMulti(Complex a) {
return new Complex(RealPart*a.RealPart,ImagePart*a.ImagePart);
}
Complex ComplexDiv(Complex a) {
if(a.RealPart==0||a.ImagePart==0) {
System.out.println("被减数不能为0");
return new Complex();
}
double d = Math.sqrt(a.RealPart*a.RealPart)+Math.sqrt(a.ImagePart*a.ImagePart);
return new Complex((RealPart*a.RealPart+ImagePart*a.ImagePart)/d,Math.round((RealPart*a.ImagePart-ImagePart*a.RealPart)/d));
}
}
- 测试代码
import static org.junit.Assert.*;
import org.junit.Test;
import junit.framework.TestCase;
public class ComplexTest extends TestCase {
Complex complex = new Complex(1,1);
@Test
public void testAdd(){
assertEquals(new Complex(3.3,3.4), complex.ComplexAdd(new Complex(2.3,2.4)));
}
//测试加法
@Test
public void testSub(){
assertEquals(new Complex(-5.3,-2.4), complex.ComplexSub(new Complex(6.3,3.4)));
}
//测试减法
@Test
public void testMulti(){
assertEquals(new Complex(3.0,2.0), complex.ComplexMulti(new Complex(3.0,2.0)));
}
//测试乘法
@Test
public void testDiv(){
assertEquals(new Complex(1.0,1.0), complex.ComplexDiv(new Complex(1.0,1.0)));
assertEquals(new Complex(0.0,0.0), complex.ComplexDiv(new Complex(1.0,0.0)));
//assertEquals(new Complex(0.0,0.0), complex.ComplexDiv(new Complex(3,4)));
//边缘测试
}
@Test
public void testequals(){
assertEquals(true, complex.equals(new Complex(1.0,1.0)));
}
//测试判断相等
}
- 运行结果截图
(四)使用StarUML对实验二中的代码进行建模
- 参考starUML教程
- 建模如下
实验总结
学习了测试代码的使用以及TDD的模式,但还不够熟练,基本上是参照老师的教程去做的。接下来要更多的练习,争取在大创中能编写较为全面的优秀的测试代码供其他成员编写算法。