实验二《Java面向对象程序设计》
实验报告封面
课程:Java程序设计 班级:1752班 姓名:曾祥杰 学号:20175221
指导教师:娄嘉鹏 实验日期:2019年4月17日
实验时间:13:45 - 15:25 实验序号:21
实验名称:面向对象程序设计
一.实验内容
1. 初步掌握单元测试和TDD
2. 理解并掌握面向对象三要素:封装、继承、多态
3. 初步掌握UML建模
4. 熟悉S.O.L.I.D原则
5. 了解设计模式
二.实验步骤
-
第一部分:初步掌握单元测试和TDD
- 在IDEA中,我们首先创建一个项目 MyUtil.java ,并输入如图代码:
- 针对 MyUtil 类我们写一个
MyUtilTest.java 的测试模块:
- 在 IDEA中我们把产品代码放在 src 中,在 IDEA中我们把产品代码放在 test 中 ,右键单击项目,在弹出的菜单中选择 New->Directory 新建一个目录并输入目录名 test 。右键单击test目录,在弹出的菜单中选择 Mark Directory as->Test Sources Root ,随后运行 MyUtilTest.java
- 在IDEA中运行结果如上,测试结果符合预期。
- 然而只有一组输入的测试是不充分的,把一般情况都测试一下,运行结果如图,测试结果符合预期:
- 我们不能只测试正常情况,下面看看异常情况如何,比如输入为负分或大于100的成绩,测试结果如下:
- 运行程序发现负分时与期望不一致,终于找到了一个bug,原因是判断不及格时没有要求成绩大于零。我们修改 MyUtil.java ,增加对负分的判断,测试结果如下:
- 一般代码在边界处最容易出错,我们还没有测试边界情况,我们对输入为“0,60,70,80,90,100”这些边界情况进行测试的代码如下:
- 我们发现边界情况中输入100时有一个Bug。我们修改 MyUtil.java ,把判断优秀的条件中包含输入为100的情况,测试结果如下:
TDD(Test Driven Devlopment, 测试驱动开发)
TDD的一般步骤如下:
- 明确当前要完成的功能,记录成一个测试列表
- 快速完成编写针对此功能的测试用例
- 测试代码编译不通过(没产品代码呢)
- 编写产品代码
- 测试通过
- 对代码进行重构,并保证测试通过(重构下次实验练习)
- 循环完成所有功能的开发
随后我们下载并配置Junit,完成后新建一个项目 MyUtil 。单击类名会出现一个灯泡状图标,选择 Create Test
- 随后选择创建JUnit3
- 我们增加测试用例 MyUtilTest ,异常情况的用例 testException ,测试边界情况的用例 testBoundary ,代码如下:
-
public class MyUtil{ public static String percentage2fivegrade(int grade){ //如果成绩小于0,转成“错误” if ((grade < 0)) return "错误"; //如果成绩小于60,转成“不及格” else if (grade < 60) return "不及格"; //如果成绩在60与70之间,转成“及格” else if (grade < 70) return "及格"; //如果成绩在70与80之间,转成“中等” else if (grade < 80) return "中等"; //如果成绩在80与90之间,转成“良好” else if (grade < 90) return "良好"; //如果成绩在90与100之间,转成“优秀” else if (grade <= 100) return "优秀"; //如果成绩大于100,转成“错误” else return "错误"; } }
import org.junit.Test; import junit.framework.TestCase; public class MyUtilTest extends TestCase { @Test public void testNormal() { assertEquals("不及格", MyUtil.percentage2fivegrade(55)); assertEquals("及格", MyUtil.percentage2fivegrade(65)); assertEquals("中等", MyUtil.percentage2fivegrade(75)); assertEquals("良好", MyUtil.percentage2fivegrade(85)); assertEquals("优秀", MyUtil.percentage2fivegrade(95)); } @Test public void testExceptions(){ assertEquals("错误", MyUtil.percentage2fivegrade(-55)); assertEquals("错误", MyUtil.percentage2fivegrade(105)); } @Test public void testBoundary(){ assertEquals("不及格", MyUtil.percentage2fivegrade(0)); assertEquals("及格", MyUtil.percentage2fivegrade(60)); assertEquals("中等", MyUtil.percentage2fivegrade(70)); assertEquals("良好", MyUtil.percentage2fivegrade(80)); assertEquals("优秀", MyUtil.percentage2fivegrade(90)); assertEquals("优秀", MyUtil.percentage2fivegrade(100)); } }
- 运行结果如下:
-
第二部分:以 TDD的方式研究学习StringBuffer
- StringBuffer的例子,代码如下:
-
import junit.framework.TestCase; import org.junit.Test; public class StringBufferDemoTest extends TestCase { StringBuffer a = new StringBuffer("StringBuffer"); StringBuffer b = new StringBuffer("StringBufferStringBuffer"); StringBuffer c = new StringBuffer("StringBufferStringBufferStringBuffer"); @Test public void testcharAt() throws Exception { assertEquals('S',a.charAt(0)); assertEquals('g',a.charAt(5)); assertEquals('r',a.charAt(11)); } @Test public void testcapacity() throws Exception { assertEquals(28,a.capacity()); assertEquals(40,b.capacity()); assertEquals(52,c.capacity()); } @Test public void testlength() throws Exception { assertEquals(12,a.length()); assertEquals(24,b.length()); assertEquals(36,c.length()); } @Test public void testindexOf() throws Exception { assertEquals(0,a.indexOf("Str")); assertEquals(5,a.indexOf("gBu")); } }
- 运行结果如下
第三部分:设计模式
面向对象的三要素
面向对象(Object-Oriented)的三要素包括:封装、继承、多态。面向对象的思想涉及到软件开发的各个方面,如面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程实现(OOP)。OOA根据抽象关键的问题域来分解系统,关注是什么(what)。OOD是一种提供符号设计系统的面向对象的实现过程,用非常接近问题域术语的方法把系统构造成“现实世界”的对象,关注怎么做(how),通过模型来实现功能规范。OOP则在设计的基础上用编程语言(如Java)编码。贯穿OOA、OOD和OOP的主线正是抽象。
S.O.L.I.D原则:
- SRP(Single ResponsibilityPrinciple,单一职责原则)
- OCP(Open-Closed Principle,开放-封闭原则)
- LSP(Liskov Substitusion Principle,Liskov替换原则)
- ISP(Interface Segregation Principle,接口分离原则)
- DIP(Dependency Inversion Principle,依赖倒置原则
设计模式四个基本要素:
- Pattern name:描述模式,便于交流,存档
- Problem:描述何处应用该模式
- Solution:描述一个设计的组成元素,不针对特例
- Consequence:应用该模式的结果和权衡(trade-offs)
其他面对对象原则:
- "组合替代继承":这是说相对于继承,要更倾向于使用组合
- "笛米特法则":这是说"你的类对其它类知道的越少越好"
- "共同封闭原则":这是说"相关类应该打包在一起"
- "稳定抽象原则":这是说"类越稳定,越应该由抽象类组成"
题目:对设计模式示例进行扩充,体会OCP原则和DIP原则的应用,初步理解设计模式。让系统支持Long类,并在MyDoc类中添加测试代码表明添加正确,提交测试代码和运行结的截图,加上学号水印
代码如下:
// Server Classes 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=20175221; } public void DisplayValue(){ System.out.println(value); } } abstract class Factory { abstract public Data CreateDataObject(); } class IntFactory extends Factory { public Data CreateDataObject(){ return new Integer(); } } class LonFactory extends Factory { public Data CreateDataObject(){ return new Long(); } } class Document { Data pd; Document(Factory pf){ pd = pf.CreateDataObject(); } public void DisplayData(){ pd.DisplayValue(); } } public class MyDoc { static Document zxj; public static void main(String[] args) { zxj=new Document(new LonFactory()); zxj.DisplayData(); } }
运行结果:
第四部分:以TDD的方式开发一个复数类Complex
要求如下:
// 定义属性并生成getter,setter double RealPart; double ImagePart; // 定义构造函数 public Complex() public Complex(double R,double I) //Override Object public boolean equals(Object obj) public String toString() // 定义公有方法:加减乘除 Complex ComplexAdd(Complex a) Complex ComplexSub(Complex a) Complex ComplexMulti(Complex a) Complex ComplexDiv(Complex a)
实验代码
public class Complex{ private double real; private double image; public Complex(double real, double image) { this.real = real; this.image = image; } public static double getRealPart(double real) { return real; } public static double getImagePart(double image) { return image; } public Complex ComplexAdd(Complex c) { return new Complex(real + c.real, image + c.image); } public Complex ComplexSub(Complex c) { return new Complex(real - c.real, image - c.image); } public Complex ComplexMulti(Complex c) { return new Complex(real * c.real - image * c.image, real * c.image + image * c.real); } public Complex ComplexDiv(Complex c) { return new Complex((real * c.image + image * c.real)/(c.image * c.image + c.real * c.real), (image * c.image + real * c.real)/(c.image * c.image + c.real * c.real)); } public String toString() { String s = " "; if (image > 0) s = real + "+" + image + "i"; if (image == 0) s = real + ""; if (image < 0) s = real + " " + image + "i"; return s; } }
测试代码
import junit.framework.TestCase; import org.junit.Test; public class ComplexTest extends TestCase { Complex a = new Complex(0.0, 2.0); Complex b = new Complex(-1.0, -1.0); Complex c = new Complex(1.0,2.0); @Test public void testgetRealPart() throws Exception { assertEquals(0.0, Complex.getRealPart(0.0)); assertEquals(-1.0, Complex.getRealPart(-1.0)); assertEquals(1.0, Complex.getRealPart(1.0)); } @Test public void testgetImagePart() throws Exception { assertEquals(2.0, Complex.getImagePart(2.0)); assertEquals(-1.0, Complex.getImagePart(-1.0)); assertEquals(2.0, Complex.getImagePart(2.0)); } @Test public void testComplexAdd() throws Exception { assertEquals("-1.0+1.0i", a.ComplexAdd(b).toString()); assertEquals("1.0+4.0i", a.ComplexAdd(c).toString()); assertEquals("0.0+1.0i", b.ComplexAdd(c).toString()); } @Test public void testComplexSub() throws Exception { assertEquals("1.0+3.0i", a.ComplexSub(b).toString()); assertEquals("-1.0", a.ComplexSub(c).toString()); assertEquals("-2.0 -3.0i", b.ComplexSub(c).toString()); } @Test public void testComplexMulti() throws Exception { assertEquals("2.0 -2.0i", a.ComplexMulti(b).toString()); assertEquals("-4.0+2.0i", a.ComplexMulti(c).toString()); assertEquals("1.0 -3.0i", b.ComplexMulti(c).toString()); } @Test public void testComplexComplexDiv() throws Exception { assertEquals("-1.0 -1.0i", a.ComplexDiv(b).toString()); assertEquals("0.4+0.8i", a.ComplexDiv(c).toString()); assertEquals("-0.6 -0.6i", b.ComplexDiv(c).toString()); } }
运行结果
码云链接(https://gitee.com/zxjacdl/zxj175221/tree/master/shiyan2)
第五部分:对实验二中的代码进行建模,发类图的截图
实验中遇到的问题
问题1:
在第一次使用TDD的那个实验中,增加MyUtil
的测试类之后,TestCase显示
红色的,但是不知道junit.jar在哪里
问题1解决方案:
上网查了才知道解决方案,步骤如下:
1.找到电脑中IDEA安装路径
2.File->Project Structure
3.点击Dependencies
,单击右上角的+,然后选择第一个JARs or directories
4.复制刚才的路径名,找到junit-4.12 jar
、 junit.jar
IDEA导入Junit4jar包(https://blog.csdn.net/zoozyy/article/details/78485965)
实验体会:
- 这次的实验对我来说还是很有难度的。
- 虽然每一步的教程都有,但期间无论是下载东西还是编写代码,都还是出现了很多难题。
- 还是在和伙伴讨论合作下完成的。希望以后的实验也可以做好
步骤 | 耗时 | 百分比 |
---|---|---|
需求分析 | 10min | 6% |
设计 | 30min | 18% |
代码实现 | 70min | 41% |
测试 | 20min | 12% |
分析总结 | 40min | 23% |