实验二 Java面向对象程序设计
课程:Java程序设计
班级:1652
姓名:孔月
学号:20165208
指导教师:娄嘉鹏
实验日期:2018.4.16
实验名称:Java面向对象程序设计
实验内容及要求:
- 初步掌握单元测试和TDD
- 理解并掌握面向对象三要素:封装、继承、多态
- 初步掌握UML建模
- 熟悉S.O.L.I.D原则
- 了解设计模式
实验内容、步骤与体会
目录:
- (一)初步掌握单元测试和TDD
- (二)以TDD的方式研究学习StringBuffer
- (三)对MyDoc类进行扩充,让其支持Boolean类,初步理解设计模式
- (四)以TDD的方式开发一个复数类Complex
- (五)使用StarUML对实验中的代码进行建模
(一)在一个MyUtil类中解决一个百分制成绩转成“优、良、中、及格、不及格”五级制成绩的功能。
根据需求伪代码应如下如果成绩小于60,转成“不及格”
如果成绩在60与70之间,转成“及格”
如果成绩在70与80之间,转成“中等”
如果成绩在80与90之间,转成“良好”
如果成绩在90与100之间,转成“优秀”
其他,转成“错误”
根据伪代码写出产品代码
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 "错误";
}
}
为测试产品代码的正确性我们需写出测试代码,此处根据实验要求将3种测试情况均写入MyutilTest中,分别包括边界测试,非法输入以及正常情况。
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(103));
assertEquals("错误", MyUtil.percentage2fivegrade(-5));
}
@Test
public void testBoundary() {
assertEquals("不及格", MyUtil.percentage2fivegrade(0));
assertEquals("及格", MyUtil.percentage2fivegrade(60));
}
}
经测试三种情况均能通过,实验效果如下图
(二)以TDD的方式研究学习StringBuffer
public class StringBufferDemo{
StringBuffer buffer = new StringBuffer();
public StringBufferDemo(StringBuffer buffer){
this.buffer = buffer;
}
public Character charAt(int i){
return buffer.charAt(i);
}
public int capacity(){
return buffer.capacity();
}
public int length(){
return buffer.length();
}
public int indexOf(String buf) {
return buffer.indexOf(buf);
}
}
public class StringBufferDemo{
StringBuffer buffer = new StringBuffer();
public StringBufferDemo(StringBuffer buffer){
this.buffer = buffer;
}
public Character charAt(int i){
return buffer.charAt(i);
}
public int capacity(){
return buffer.capacity();
}
public int length(){
return buffer.length();
}
public int indexOf(String buf) {
return buffer.indexOf(buf);
}
}
通过网上查阅资料学习得出了以上四种的功能
charAt(int i)
的功能为返回此序列中指定索引处的 char 值。第一个 char 值在索引 0 处,第二个在索引 1 处,依此类推,这类似于数组索引。capacity()
返回的是字符串缓冲区的容量length()
针对字符串String说的,用来求数组中某个元素的字符串长度indexOf(Strings)
为返回输入的子字符串的第一个字母在母字符串的位置。
根据四个方法的功能,编写出一个测试代码来看断言值与方法返回值是否相等。
import org.junit.Test;
import junit.framework.TestCase;
import static org.junit.Assert.*;
public class StringBufferDemoTest extends TestCase {
StringBuffer a = new StringBuffer("kongyue");
StringBuffer b = new StringBuffer("kongyue studied JAVA");
StringBuffer c = new StringBuffer("Now kongyue is studying JAVA");
@Test
public void testcharAt() throws Exception{
assertEquals('k',a.charAt(0));
assertEquals('y',a.charAt(4));
assertEquals('e',a.charAt(6));
}
@Test
public void testcapacity() throws Exception{
assertEquals(23,a.capacity());
assertEquals(36,b.capacity());
assertEquals(44,c.capacity());
}
@Test
public void testlength() throws Exception{
assertEquals(7,a.length());
assertEquals(20,b.length());
assertEquals(28,c.length());
}
@Test
public void testindexOf() throws Exception{
assertEquals(0,a.indexOf("kon"));
assertEquals(8,b.indexOf("stu"));
assertEquals(24,c.indexOf("JAVA"));
}
}
经运行测试代码通过,效果如图
(三)对MyDoc类进行扩充,让其支持Boolean类,初步理解设计模式
我的题目为:让系统支持Boolean类,并在MyDoc类中添加测试代码表明添加正确,代码如下:
abstract class Data {
abstract public void DisplayValue();
}
class Integer extends Data {
int value;
Integer() {
value=5208;
}
public void DisplayValue(){
System.out.println (value);
}
}
class Boolean extends Data {
boolean flag;
Boolean() {
flag = true;
}
public void DisplayValue(){
System.out.println (flag);
}
}
// Pattern Classes
abstract class Factory {
abstract public Data CreateDataObject();
}
class IntFactory extends Factory {
public Data CreateDataObject(){
return new Integer();
}
}
class BooleanFactory extends Factory {
public Data CreateDataObject(){
return new Boolean();
}
}
class Document {
Data data;
Document(Factory factory) {
data = factory.CreateDataObject();
}
public void DisplayData() {
data.DisplayValue();
}
}
public class MyDoc {
static Document d;
public static void main(String[] args) {
d = new Document(new IntFactory());
d.DisplayData();
d = new Document(new BooleanFactory());
d.DisplayData();
}
}
最终运行效果如图
(四)以TDD的方式开发一个复数类Complex
测试代码
public class ComplexTest extends TestCase {
Complex c1 = new Complex(0, 3);
Complex c2 = new Complex(-1, -1);
Complex c3 = new Complex(2,1);
@Test
public void testgetRealPart() throws Exception {
assertEquals(-1.0, Complex.getRealPart(-1.0));
assertEquals(5.0, Complex.getRealPart(5.0));
assertEquals(0.0, Complex.getRealPart(0.0));
}
@Test
public void testgetImagePart() throws Exception {
assertEquals(-1.0, Complex.getImagePart(-1.0));
assertEquals(5.0, Complex.getImagePart(5.0));
assertEquals(0.0, Complex.getImagePart(0.0));
}
@Test
public void testComplexAdd() throws Exception {
assertEquals("-1.0+2.0i", c1.ComplexAdd(c2).toString());
assertEquals("2.0+4.0i", c1.ComplexAdd(c3).toString());
assertEquals("1.0", c2.ComplexAdd(c3).toString());
}
@Test
public void testComplexSub() throws Exception {
assertEquals("1.0+4.0i", c1.ComplexSub(c2).toString());
assertEquals("-2.0+2.0i", c1.ComplexSub(c3).toString());
assertEquals("-3.0 -2.0i", c2.ComplexSub(c3).toString());
}
@Test
public void testComplexMulti() throws Exception {
assertEquals("3.0 -6.0i", c1.ComplexMulti(c2).toString());
assertEquals("-3.0+9.0i", c1.ComplexMulti(c3).toString());
assertEquals("-1.0 -3.0i", c2.ComplexMulti(c3).toString());
}
@Test
public void testComplexComplexDiv() throws Exception {
assertEquals("-1.5 -1.5i", c1.ComplexDiv(c2).toString());
assertEquals("1.2+0.6i", c1.ComplexDiv(c3).toString());
assertEquals("-0.6 -0.6i", c2.ComplexDiv(c3).toString());
}
}
产品代码
import java.util.Scanner;
import java.lang.String;
public class Complex{
double RealPart;
double ImagePart;
public Complex(double R, double I) {
this.RealPart = R;
this.ImagePart = I;
}
public static double getRealPart(double RealPart) {
return RealPart;
}
public static double getImagePart(double ImagePart) {
return ImagePart;
}
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) {
double RealPart2=RealPart+ a.RealPart;
double ImagePart2=ImagePart + a.ImagePart;
return new Complex(RealPart2,ImagePart2);
}
Complex ComplexSub(Complex a) {
double RealPart2=RealPart - a.RealPart;
double ImagePart2=ImagePart - a.ImagePart;
return new Complex(RealPart2,ImagePart2);
}
Complex ComplexMulti(Complex a) {
double RealPart2= RealPart* a.RealPart- ImagePart * a.ImagePart;
double ImagePart2=ImagePart * a.ImagePart+ImagePart * a.RealPart;
return new Complex(RealPart2,ImagePart2);
}
Complex ComplexDiv(Complex a) {
double RealPart2= (RealPart * a.ImagePart+ ImagePart * a.RealPart)/(a.ImagePart * a.ImagePart + a.RealPart * a.RealPart);
double ImagePart2=(ImagePart * a.ImagePart + RealPart * a.RealPart)/(a.ImagePart * a.ImagePart + a.RealPart * a.RealPart);
return new Complex(RealPart2,ImagePart2);
}
}
测试效果如下图
(五)使用StarUML对实验中的代码进行建模
利用工具WhiteStarUML进行建模,效果如下图
原有上交截图
注意对于抽象类和抽象方法要用斜体表明,这点在做实验时是我没有考虑到的,更改后的
问题总结与体会
- 问题1:本次实验大量利用JUnit测试用例来校验代码,在这个过程中我按照老师博客的操作进行,但是仅显示Test passed而不会产生green bar,当我故意改写代码使其出错时,运行会出现代码错误提示,故而测试代码应该是没有问题,这个问题我也有与同学探讨过,但是没有得出一个合理的解释,在网上查询了有关不会出现green bar的原因后,发现解决方案也并不适用于我的实验问题。
- 问题2:对于Complex复数类,在检测时只能通过3个测试用例,根据反馈查错发现原代码在
string=RealPart+ImagePart+"i"
中默认将前两个变量先进行了求和运算,未起到原有目的,后改进为string=RealPart+" "+ImagePart+"i"
即可进行运算
-
问题3:除了代码编写上的问题,在导包时我也遇到了问题,在安装下载时我未找到和实验要求一样的下载包,选择了最相近的,所以也不是很确定后续试验中操作的green bar没有及时出现是否与此有关
-
除此之外尽管实验过程中在程序的编写上我遇到了很多困难,譬如在对MyDoc类进行扩充,让其支持Boolean类时如何合法定义有关变量的类型,以及复数类Complex的编写,过程很痛苦,但是学会了这种通过先写伪代码再利用测试代码辅助完成产品代码的方法,对于编程来说真的很方便,而且对于各种情况的监测利用Junit测试十分方便。
步骤 | 耗时 | 百分比 |
---|---|---|
需求分析 | 25 min | 8.3% |
设计 | 70 min | 23.3% |
代码实现 | 120 min | 40% |
测试 | 40 min | 13.3% |
分析总结 | 45 min | 15% |