实验楼第二次试验报告

实验楼第二次试验报告

北京电子科技学院(BESTI

              

课程:Java程序设计  班级:1353  姓名:李雪琦  学号:20135309

成绩:               指导教师:娄嘉鹏     实验日期:2015.5.6

实验密级:      预习程度:        实验时间:

仪器组次:      必修/选修:选修     实验序号:2

实验名称:             Java面向对象程序设计                                               

实验目的与要求:

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

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

3. 初步掌握UML建模

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

5. 了解设计模式

6. 没有Linux基础的同学建议先学习《Linux基础入门(新版)》《Vim编辑器》课程。

 

实验仪器:

名称

型号

数量

PC

 Lenovo

1

虚拟机

实验楼

1

 

实验内容、步骤与体会(附纸):

(一)单元测试

(1) 三种代码

编程是智力活动,不是打字,编程前要把干什么、如何干想清楚才能把程序写对、写好。与目前不少同学一说编程就打开编辑器写代码不同,我希望同学们养成一个习惯,当你们想用程序解决问题时,要会写三种码:

  • 伪代码
  • 产品代码
  • 测试代码

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

TDD的一般步骤如下:

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

1.打开Eclipse,单击File->New->Java Project新建一个TDDDemo的Java项目,

2.我们在TDDDemo项目中,把鼠标放到项目名TDDDemo上,单击右键,在弹出的菜单中选定New->Source Folder新建一个测试目录test,

3.我们把鼠标放到test目录上,单击右键,在弹出的菜单中选定New->JUnit Test Case新建一个测试用例类MyUtilTest,

4.我们增加第一个测试用例testNormal,注意测试用例前一定要有注解@Test,测试用例方法名任意,

5.图中的红叉说明代码存在语法错误,原因很简单,MyUtil类还不存在,类中的percentage2fivegrade方法也不存在,我们在TDDDemo的src目录中新建一个MyUtil的类,并实现percentage2fivegrade方法,

6.大家可以看到现在测试代码没有语法错误了,我们把鼠标放到MyUtilTest.java上,单击右键,选择Run as->JUnit Test,

7.测试结果出现了一个红条(red bar,说明测试没通过,红条上面汇总了测试情况,运行了一个测试,没有错误,一个测试没通过。下面原因说的也很清楚:测试代码第十行传入55时,期望结果是不及格,代码返回了错误,修改MyUtil.Java吧,

8.测试结果出现了一个绿条(green bar,说明测试通过了。TDD的目标是"Clean Code That Works"TDDslogan"Keep the bar green, to Keep the code clean",大家体会一下。

TDD的编码节奏是:

  • 增加测试代码,JUnit出现红条
  • 修改产品代码
  • JUnit出现绿条,任务完成

我们增加一个测试异常情况的用例testException,

我们增加一个测试边界情况的用例testBoundary,

 

 

(二)面向对象三要素

1)抽象

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

2)封装、继承与多态

面向对象(Object-Oriented)的三要素包括:封装、继承、多态。面向对象的思想涉及到软件开发的各个方面,如面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程实现(OOP)OOA根据抽象关键的问题域来分解系统,关注是什么(whatOOD是一种提供符号设计系统的面向对象的实现过程,用非常接近问题域术语的方法把系统构造成现实世界的对象,关注怎么做(how,通过模型来实现功能规范。OOP则在设计的基础上用编程语言(如Java)编码。贯穿OOAOODOOP的主线正是抽象。
OOD中建模会用图形化的建模语言UMLUnified Modeling Language,UML是一种通用的建模语言,我们实验中使用umbrello进行建模,Windows中推荐大家使用StarUML

过程抽象的结果是函数,数据抽象的结果是抽象数据类型(Abstract Data TypeADT),类可以作具有继承和多态机制的ADT数据抽象才是OOP的核心和起源。

OO三要素的第一个要素是封装,封装就是将数据与相关行为包装在一起以实现信息就隐藏。

封装实际上使用方法(method)将类的数据隐藏起来,控制用户对类的修改和访问数据的程度,从而带来模块化(Modularity)和信息隐藏(Information hiding)的好处;接口(interface是封装的准确描述手段。

1.我们可以用UML中的类图来描述类Dog,首先我们在实验楼的环境中打开shell,在命令行中输入umbrello,打开UML建模软件umbrello,

 

2.先单击工具栏上的类图标,再在class diagram(类图)中单击一下,会弹出一个圣诞框,输入类名Dog,

3.我们把鼠标放到Dog类上,单击右键,选择Properties,在弹出的对话框中的Display中去掉Public Only选项,

4.我们把鼠标放到Dog类上,单击右键,选择New->Attribute,在弹出的对话框中的填好Type,Name,并选好Visibility,

5.我们把鼠标放到Dog类上,单击右键,选择New->Operation,在弹出的对话框中的填好Type,Name,并选好Visibility,

6.我们可以看到,在UML 里,一个类的属性能显示它的名字,类型,初始化值,属性也可以显示privatepublicprotected。 类的方法能显示它们的方法名,参数,返回类型,以及方法的privatepublicprotected属性。其中:

  • +表示public
  • #表示 protected
  • -表示 private

使用UML可以让我们不必关注细节。同样,我们可以建立一个Cat类(请大家模仿Dog类实现Cat)

 

(三)设计模式初步

1S.O.L.I.D原则

面向对象三要素是封装、继承、多态,任何面向对象编程语言都会在语法上支持这三要素。如何借助抽象思维用好三要素特别是多态还是非常困难的,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.
  • 软件实体(类,模块,函数等)应该对扩充开放,对修改封闭。

对扩充开放(Open For Extension )要求软件模块的行为必须是可以扩充的,在应用需求改变或需要满足新的应用需求时,我们要让模块以不同的方式工作; 对修改封闭(Closed for Modification )要求模块的源代码是不可改动的,任何人都不许修改已有模块的源代码。 基于OCP,利用面向对象中的多态性(Polymorphic),更灵活地处理变更拥抱变化,OCP可以用以下手段实现:(1)抽象和继承,(2)面向接口编程。
比如,在一个图形系统中,已经存在三个模块Shape,Square,Circle,

用户现大需要一个Triangle模块是一个合理的要求,由于我们使用了多态,原先的模块不需要改变,只要新增加一个模块Triangle就可以了,

这个图形系统是符合OCP原则的。

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
  • 子类必须可以被其基类所代
  • 使用指向基类的指针或引用的函数,必须能够在不知道具体派生类对象类型的情况下使用它

LSP的核心思想是父类型对象可以被子类型对象所取代。

ISP的内容是:

  • Clients should not be forced to depend upon interfaces that they do not use
  • 客户不应该依赖他们并未使用的接口

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
  • 高层模块不应该依赖于低层模块。二者都应该依赖于抽象
  • 抽象不应该依赖于细节。细节应该依赖于抽象

通过接口或者抽象类,DIP在应用中通过依赖注入的方式实现解耦,重用低级模块,重用实现,解除依赖。

这样,上层函数copy依赖下层函数read,write。
DIP改变了依赖的方向,要求下面依赖上面,我们使用抽象类实现DIP,

2)模式与设计模式

模式是某外在环境(Context) 下﹐对特定问题(Problem)的惯用解决之道(Solution)。模式必须使得问题明晰,阐明为什么用它来求解问题,以及在什么情况下有用,什么情况下不能起作用,每个模式因其重复性从而可被复用,本身有自己的名字,有可传授性,能移植到不同情景下。模式可以看作对一个问题可复用的专家级解决方法。
计算机科学中有很多模式:

  • GRASP模式
  • 分析模式
  • 软件体系结构模式
  • 设计模式:创建型,结构型,行为型
  • 管理模式: The Manager Pool 实现模式
  • 界面设计交互模式

这里面最重要的是设计模式,在面向对象中设计模式的地位可以和面向过程编程中的数据结构的地位相当。

3)设计模式实示例

设计模式(design pattern)提供一个用于细化软件系统的子系统或组件,或它们之间的关系图,它描述通信组件的公共再现结构,通信组件可以解决特定语境中的一个设计问题。

如图,随着系统中对象的数量增多,对象之间的交互成指数增长,设计模式可以帮我们以最好的方式来设计系统。设计模式背后是抽象和SOLID原则。
设计模式有四个基本要素:

  • Pattern name:描述模式,便于交流,存档
  • Problem:描述何处应用该模式
  • Solution:描述一个设计的组成元素,不针对特例
  • Consequence:应用该模式的结果和权衡(trade-offs

Java类库中大量使用设计模式:

  • Factoryjava.util.Calendar
  • Compsitejava.awt.Container
  • Decoratorjava I/0
  • Iteratorjava.util.Enumeration
  • Strategyjava.awt.LayoutManager

SOLID原则外还有很多其它的面向对象原则。如:

  • "组合替代继承":这是说相对于继承,要更倾向于使用组合;
  • "笛米特法则":这是说"你的类对其它类知道的越少越好"
  • "共同封闭原则":这是说"相关类应该打包在一起"
  • "稳定抽象原则":这是说"类越稳定,越应该由抽象类组成";

当然,这些原则并不是孤立存在的,而是紧密联系的,遵循一个原则的同时也就遵循了另外一个或多个原则;反之,违反了其中一个原则也很可能同时就违反了另外一个或多个原则。 设计模式是这些原则在一些特定场景的应用结果。因此,可以把设计模式看作"框架",把OOD原则看作"规范"。 在学习设计模式的过程中,要经常性的反思,这个设计模式体现了面向对象设计原则中的哪个或哪一些原则。

(四)练习

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

2.实验报告中统计自己的PSP(Personal Software Process)时间

步骤 耗时 百分比 |
|:--------:|:--------:|:---------:|
需求分析 | | |
设计 | | |
代码实现 | | |
测试 | | |
分析总结 | | |

3. 实现要有伪代码,产品代码,测试代码。

4.总结单元测试的好处

伪代码:

无输入 --- 则复数的实部为0,虚部为0

仅输入实部 --- 复数的实部为所输入的实部,虚部为0

仅输入虚部 --- 复数的实部为0,虚部为所输入的虚部

实部虚部都输入 --- 复数的实部与虚部对应相应输入的实部虚部。

加法 --- 复数的实部与实部相加,虚部与虚部相加 ,即输出p1.rePart+p2.rePart,p1.imPart+p2.imPart

减法 --- 复数的实部与实部相减,虚部与虚部相减 , 即输出 p1.rePart-p2.rePart,p1.imPart-p2.imPart

产品代码:

package Exercise;

public class Complex

double rePart,imPart; 
Complex() 

this.rePart=0; 
this.imPart=0; 

Complex(double rePart) 

this.rePart=rePart; 
this.imPart=0; 

Complex(double rePart,double imPart) 

this.rePart=rePart; 
this.imPart=imPart; 

Complex Jia(Complex p1,Complex p2) 

Complex p =new Complex(p1.rePart+p2.rePart,p1.imPart+p2.imPart);
return p; 

Complex Jian(Complex p1,Complex p2) 

Complex p =new Complex(p1.rePart-p2.rePart,p1.imPart-p2.imPart);
return p;

void Print() 

System.out.println("复数的值为:");
if(this.imPart!=0)
System.out.println(this.rePart+"+"+this.imPart+"i"); 
else System.out.println(this.rePart); 

}

测试代码:

package Exercise;

public class Test 

public static void main(String[] args) 

Complex c=new Complex(); 
Complex c1=new Complex(3,6);
Complex c2=new Complex(6,3); 
c1.Print(); 
c2.Print(); 
System.out.println("这两复数和为:"); 
System.out.println((c.Jia(c1, c2).rePart+"+"+c.Jia(c1, c2).imPart+"i").toString()); 
System.out.println("这两复数差为:"); 
System.out.println(c.Jian(c1, c2).rePart+"+"+c.Jian(c1, c2).imPart+"i");

}  

遇到的问题及解决方法:

1.按步骤调试了MyUtil.Java后并没有如期出现绿条,后来又进一步修改了grade的范围才出现绿条。

2.在Umbrello中UML图是可以转化成Java代码的,有Java代码也可以生成UML图的。但还不知道具体怎么做,需要课下进一步学习。

3.这次实验内容比较多,学习到了许多理论和原则,另外软件使用也不熟练。需要之后用更多的时间消化学习。

 

原文地址:https://www.cnblogs.com/lxq20135309/p/4486546.html