20145216史婧瑶《Java程序设计》第二次实验报告

实验二 Java面向对象程序设计

实验内容

1. 初步掌握单元测试和TDD

2. 理解并掌握面向对象三要素:封装、继承、多态

3. 初步掌握UML建模

4. 熟悉S.O.L.I.D原则

5. 了解设计模式

实验步骤

(一)单元测试

(1) 三种代码

  • 伪代码

    百分制转五分制:
    如果成绩小于60,转成“不及格”
    如果成绩在60与70之间,转成“及格”
    如果成绩在70与80之间,转成“中等”
    如果成绩在80与90之间,转成“良好”
    如果成绩在90与100之间,转成“优秀”
    其他,转成“错误”
    
  • 产品代码
    public class MyUtil{
       public static String percentage2fivegrade(int grade){
           //如果成绩小于60,转成“不及格”
           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 "优秀";
           //其他,转成“错误”
           else
               return "错误";
       }
    }
    
  • 测试代码

1、50分测试:

    public class MyUtilTest {
    public static void main(String[] args) {
            // 百分制成绩是50时应该返回五级制的“不及格”
            if(MyUtil.percentage2fivegrade(50) != "不及格")
                System.out.println("test failed!");
            else
                System.out.println("test passed!");
        }
    }

运行结果:

2、正常情况测试:

    public class MyUtilTest {
        public static void main(String[] args) {
             //测试正常情况
             if(MyUtil.percentage2fivegrade(55) != "不及格")
                 System.out.println("test failed!");
             else if(MyUtil.percentage2fivegrade(65) != "及格")
                 System.out.println("test failed!");
             else if(MyUtil.percentage2fivegrade(75) != "中等")
                 System.out.println("test failed!");
             else if(MyUtil.percentage2fivegrade(85) != "良好")
                 System.out.println("test failed!");
             else if(MyUtil.percentage2fivegrade(95) != "优秀")
                 System.out.println("test failed!");
             else
                 System.out.println("test passed!");
         }
     }

运行结果:

3、异常情况测试:

    public class MyUtilTest {
        public static void main(String[] args) {
            //测试出错情况
            if(MyUtil.percentage2fivegrade(-10) != "错误")
                System.out.println("test failed 1!");
            else if(MyUtil.percentage2fivegrade(115) != "错误")
                System.out.println("test failed 2!");
            else
                System.out.println("test passed!");
        }
    }

运行结果:

4、增加判断负分的情况:

    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 "错误";
       }
    }

运行结果:

5、测试边界情况:

    public class MyUtilTest {
        public static void main(String[] args) {
            //测试边界情况
            if(MyUtil.percentage2fivegrade(0) != "不及格")
               System.out.println("test failed 1!");
            else if(MyUtil.percentage2fivegrade(60) != "及格")
                System.out.println("test failed 2!");
            else if(MyUtil.percentage2fivegrade(70) != "中等")
                System.out.println("test failed 3!");
            else if(MyUtil.percentage2fivegrade(80) != "良好")
                System.out.println("test failed 4!");
            else if(MyUtil.percentage2fivegrade(90) != "优秀")
                System.out.println("test failed 5!");
            else if(MyUtil.percentage2fivegrade(100) != "优秀")
                System.out.println("test failed 6!");
            else
                System.out.println("test passed!");
        }
    }

运行结果:

6、增加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 "错误";
       }
    }

运行结果:

(2) TDD(Test Driven Devlopment, 测试驱动开发)

先写测试代码,然后再写产品代码的开发方法叫“测试驱动开发”(TDD)。TDD的一般步骤如下:

  • 明确当前要完成的功能,记录成一个测试列表
  • 快速完成编写针对此功能的测试用例
  • 测试代码编译不通过(没产品代码呢)
  • 编写产品代码
  • 测试通过
  • 对代码进行重构,并保证测试通过(重构下次实验练习)
  • 循环完成所有功能的开发

具体示例:

1 创建新的项目

创建名为UnitTestingApp的Java项目。

2 创建一个类进行测试

创建一个新的类用于测试。

添加方法sayHello返回Hello字符串。

3 创建测试源根目录

为了不将测试添加到源中,用户可以创建根目录。在这种情况下测试将从产品代码中分离出来。

创建一个测试源根目录。

4 创建一个测试类

IntelliJ IDEA提供了一个快捷操作Cmd + Shift + T作为类和测试之间的导航。同时允许用户在那里创建一个测试类。

选择JUnit 4作为单元测试库。IntelliJ IDEA将提供到件这个库添加到模块中。选择生成setUp和sayHello的方法。

当测试类生成后,我们可以为我们的测试方法testSayHello添加代码。

5 运行测试

现在我们可以通过右键菜单在这个类上运行‘MyClassTest‘来进行测试,或通过Run → Edit Configurations来进行。

结果将在Run工具窗口进行显示。

(二)面向对象三要素

(1)抽象

  • 抽象一词的本意是指人在认识思维活动中对事物表象因素的舍弃和对本质因素的抽取。
  • 抽象是人类认识复杂事物和现象时经常使用的思维工具,抽象思维能力在程序设计中非常重要,"去粗取精、化繁为简、由表及里、异中求同"的抽象能力很大程度上决定了程序员的程序设计能力。
  • 抽象就是抽出事物的本质特征而暂时不考虑他们的细节,对于复杂系统问题人们借助分层次抽象的方法进行问题求解。在抽象的最高层,可以使用问题环境的语言,以概括的方式叙述问题的解;在抽象的较低层,则采用过程化的方式进行描述。在描述问题解时,使用面向问题和面向实现的术语。
  • 程序设计中,抽象包括两个方面,一是过程抽象,二是数据抽象。

(2)封装、继承与多态

  • 面向对象(Object-Oriented)的三要素包括:封装、继承、多态。
  • 面向对象的思想涉及到软件开发的各个方面,如面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程实现(OOP)。
  • OOA根据抽象关键的问题域来分解系统,关注是什么(what)。
  • OOD是一种提供符号设计系统的面向对象的实现过程,用非常接近问题域术语的方法把系统构造成“现实世界”的对象,关注怎么做(how),通过模型来实现功能规范。OOP则在设计的基础上用编程语言(如Java)编码。
  • 贯穿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,依赖倒置原则)

(四)练习

使用TDD的方式设计关实现复数类Complex

  • 伪代码:

    定义复数的实部和虚部(均为双精度);
    
    构造方法分别取得复数的实部和虚部;
    
    构造两个复数相加的函数,并返回结果;
    
    构造两个复数相减的函数,并返回结果;
    
    构造两个复数相乘的函数,并返回结果;
    
    构造两个复数相除的函数,并返回结果;
    
  • 产品代码:

    public class Complex
    {
        double real,img;        //实部和虚部
    
        public Complex()        //默认构造方法
        {
            this.real=0;
            this.img =0;
        }
        public Complex(double real,double img)    //带参数的构造方法
        {
            this.real=real;
            this.img =img;
        }
        public double getReal()
        {
            return this.real;
        }        //得到实部
    
        public double getImage()
        {
             return this.img;
        }        //得到虚部
        public double getReal(Complex c)
        {
            return c.real;
        }        //得到复数c的实部
    
        public double getImage(Complex c)
        {
            return c.img;
        }        //得到复数c的虚部
    
        public void setReal    (double real)
        {
            this.real=real;
        }        //设置实部
    
        public void setImage(double img)
        {
            this.img =img;
        }        //设置虚部
    
        public Complex addComplex(Complex a,Complex b)    //两个复数相加,结果返回
        {
            Complex temp =new Complex();
            temp.real=a.real+b.real;
            temp.img =a.img +b.img;
            return temp;
        }
    
        public Complex decComplex(Complex a,Complex b)    //两个复数相减,结果返回
        {
            Complex temp = new Complex();
            temp.real = a.real - b.real;
            temp.img  = a.img  - b.img;
            return temp;
        }
    
        public Complex mulComplex(Complex a,Complex b)    //两个复数相乘,结果返回
        {
            Complex temp = new Complex();
            temp.real = a.real*b.real-a.img*b.img;
            temp.img    = a.real*b.img+a.img*b.real;
            return temp;
        }
    
        public Complex divComplex(Complex a,Complex b)    //两个复数相除,结果返回
        {
            Complex temp = new Complex();
            temp.real=(a.real*b.real+a.img*b.img)/(b.real*b.real+b.img*b.img);
            temp.img =(a.img*b.real-a.real*b.img)/(b.real*b.real+b.img*b.img);
            return temp;
        }
    
        public void printComplex()
        {
            System.out.println(""+this.real+"+"+this.img+"i");
        }        //输出结果
    
        public String toString()
        {
            String fin=" ";
            if(img>0)
            {
                fin = real+"+"+img+"i";
            }
            else if(img<0)
            {
                fin = real+ ""+img+"i";
            }
            else
            {
                fin = fin;
            }
            return  fin;
    }
    
  • 测试代码:

    public static void main(String[] args)
    {
            Complex cc = new Complex(2, 6);
            cc.printComplex();
            Complex dd = new Complex(1, 1);
            dd.printComplex();
            System.out.println("-----------------");
    
            Complex ff = new Complex();
            ff = ff.addComplex(cc, dd);
            ff.printComplex();
            ff = ff.decComplex(cc, dd);
            ff.printComplex();
            ff = ff.mulComplex(cc, dd);
            ff.printComplex();
            ff = ff.divComplex(cc, dd);
            ff.printComplex();
            System.out.println("-----------------");
    }
  • 用starUML软件建模复数类Complex:

  • 分块测试截图:

1、加法:

2、减法:

3、乘法:

4、除法:

  • PSP时间:

步骤 耗时 百分比
需求分析 30min  16.7% 
设计  60min  33.3%
代码实现 45min  25% 
测试 15min  8.3% 
分析总结 30min  16.7%
  • 单元测试的好处:

1、它是一种验证行为。

程序中的每一项功能都是测试来验证它的正确性。它为以后的开发提供支缓。就算是开发后期,我们也可以轻松的增加功能或更改程序结构,而不用  担心这个过程中会破坏重要的东西。而且它为代码的重构提供了保障。这样,我们就可以更自由的对程序进行改进。

2、它是一种设计行为。

编写单元测试将使我们从调用者的角度观察、思考。特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,即迫使我们解除软件中的耦合。

3、它是一种编写文档的行为。

单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。

4、它具有回归性。

自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。

时间: 2024-07-31 14:25:33

20145216史婧瑶《Java程序设计》第二次实验报告的相关文章

java程序设计第二次实验报告

北京电子科技学院(BESTI) 实验报告 课程:数据结构    班级:1352    姓名:何伟钦     学号:20135223 成绩:            指导教师:娄嘉鹏      实验日期: 2015.5.6 实验密级:         预习程度:             实验时间:5:30-10:00 仪器组次:23   必修/选修:必修       实验序号:02 实验名称:Java面向对象程序设计 实验目的与要求:1.初步掌握单元测试和TDD 2.理解并掌握面向对象三要素:封装.

20145216史婧瑶《信息安全系统设计基础》第十一周学习总结

20145216史婧瑶<信息安全系统设计基础>第十一周学习总结 教材内容总结 第八章 异常控制流 平滑:指在存储器中指令都是相邻的. 突变:出现不相邻,通常由诸如跳转.调用.和返回等指令造成. 异常控制流ECF:即这些突变. 关于ECF: 1.ECF是操作系统用来实现I/O.进程和虚拟存器的基本机制 2.应用程序通过使用一个叫做陷阱或者系统调用的ECF形式,向操作系统请求服务 3.ECF是计算机系统中实现并发的基本机制 4.软件异常机制--C++和Java有try,catch,和throw,C

20145216史婧瑶《信息安全系统设计基础》第3周学习总结

20145216史婧瑶<信息安全系统设计基础>第3周学习总结 教材学习内容总结 十六进制表示法C表示法以0x或0X开头的数字常量为十六进制进制转换常用进制:二进制(B),十进制(D),八进制(O或者Q),十六进制(H) 转换为二进制-十六进制相互转换,二进制的四位数字对应十六进制的一位数字. 同理,二进制与八进制的转化是三位对应一位. 但是通常情况下,进制转换都以二进制为桥梁进行转换. 对于一个字长为w位的机器来说,虚拟地址的范围是0~2^w-1.程序最多访问2的w次方个字节. 数据大小: 在

20145216史婧瑶《信息安全系统设计基础》第九周学习总结

20145216史婧瑶<信息安全系统设计基础>第九周学习总结 教材内容总结 第十章 系统级I/O 输入/输出(I/O)是在主存和外部设备之间拷贝数据的过程. 第一节 Unix I/O 这一节涉及到操作系统的基本抽象之一--文件.也就是说,所有的I/O设备都被模型化为文件,而所有的输入输出都被当做对相应文件的读/写.相关的执行动作如下: 1.打开文件: 应用程序向内核发出请求→要求内核打开相应的文件→内核返回文件描述符 文件描述符:一个小的非负整数,用来在后续对此文件的所有操作中标识这个文件.有

20145216史婧瑶 《信息安全系统设计基础》第2周学习总结

20145216史婧瑶 <信息安全系统设计基础>第2周学习总结 教材学习内容总结 一.VIM 1.hjkl所表示的即为光标 ←↓↑→,前提是要在normal的状态下.方便记忆j像一个笔就像下箭头. ·i → Insert 模式,可插入文本.按 ESC 回到 Normal 模式. ·A → 输入欲添加文本(在一行后添加文本).按 ESC 回到 Normal 模式. ·x → 删当前光标所在的一个字符. ·:wq → 存盘 + 退出 (:w 存盘, :q 退出) 2.删除类命令: 该命令为操作符d

20145216史婧瑶《信息安全系统设计基础》第7周学习总结

20145216史婧瑶<信息安全系统设计基础>第七周学习总结 教材内容总结 第六章 存储器层次结构 存储器系统是一个具有不同容量.成本和访问时间的存储设备的层次结构. CPU寄存器.高速缓存存储器.主存储器.磁盘. 第一节 存储技术 一.随机访问存储器(RAM) 1.RAM分类: 静态的SRAM-更快,更贵,作为高速缓存存储器,CPU片上或片下 动态的DARM-作为主存以及图形系统的帧缓冲区 2.非易失性存储器--ROM (1)分类 PROM-可编程ROM,只能被编程一次 EPROM-可擦写可

20145216史婧瑶《信息安全系统设计基础》第6周学习总结

20145216史婧瑶<信息安全系统设计基础>第6周学习总结 教材内容总结 第四章 处理器体系结构 第一节 Y86指令集体系结构 一.程序员可见的状态 1.含义:每条指令都会读取或修改处理器状态的某些部分 2."程序员":可以是用汇编代码写程序的人,也可以是产生机器级代码的编译器 3.具体的处理器状态:类似于IA32 有8个程序寄存器:%eax,%ecx,%edx,%ebx,%esi,%edi,%esp,%ebp 处理器的每个程序寄存器存储一个字 寄存器%esp被入栈.出栈

20145216史婧瑶《网络对抗》网络欺诈技术防范

20145216史婧瑶<网络对抗>网络欺诈技术防范 实验问题回答 (1)通常在什么场景下容易受到DNS spoof攻击 攻击者能对在同一网段可以ping通的电脑发起DNS spoof攻击,所以一般在连接公用Wi-Fi的情况下电脑容易受到DNS spoof攻击. (2)在日常生活工作中如何防范以上两种攻击方法 1.尽量避免连接公用Wi-Fi2.在访问网站时注意观察它的IP地址 实验总结与体会 这次实验我遇到了许多问题,第一个是我做简单应用SET工具建立冒名网站这个实验的时候,第一次克隆的是腾讯页

20145216史婧瑶《网络对抗》Web安全基础实践

20145216史婧瑶<网络对抗>Web安全基础实践 实验问题回答 (1)SQL注入攻击原理,如何防御 攻击原理: SQL注入攻击指的是通过构建特殊的输入作为参数传入web应用程序,而这些输入大都是SQL语法里的一些组合,程序通过执行SQL语句进而执行攻击者所要的操作.其主要原因是程序没有细致的过滤用户输入的数据,致使非法数据侵入系统. 防御方法: 对输入的数据进行过滤,将常见的sql语句的关键词:select or ' " 等字符进行过滤. 对在数据库中对密码进行加密,验证登陆的时

20145216史婧瑶《网络对抗》逆向及Bof进阶实践

20145216史婧瑶<网络对抗>逆向及Bof进阶实践 基础知识 Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈的返回地址利用缓冲区溢出,覆盖成为指向 shellcode的地址. Linux中两种基本构造攻击buf的方法:retaddr+nop+shellcode ,nop+shellcode+retaddr ,缓冲区小就就把shellcode放后边,不然就放前边. 实验步骤 1.准备一段shellcode代码 2.设置环境 Bof攻击防御