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

目录

一、单元测试和TDD

用程序解决问题时,要学会写以下三种代码:

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

正确的顺序应为:伪代码(思路)→ 测试代码(产品预期功能)→ 产品代码(实现预期功能),这种开发方法叫“测试驱动开发”(TDD)。TDD的一般步骤如下:

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

基于TDD,可以有效避免过度开发的现象,因为我们只需要让测试通过即可。

任务一:实现百分制成绩转成“优、良、中、及格、不及格”五级制成绩的功能

以这个任务为例,我们来对TDD方法进行一次小小的实践。

首先要明白自己的程序需要进行哪些操作?要实现什么目标?伪代码可以帮我们理清思路。

百分制转五分制:
如果成绩小于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 "错误";
}
}

产品代码是为用户提供的,为了保证正确性,我们需要对自己的程序进行测试,考虑所有可能的情况,来判断结果是否合乎要求。这是我们就需要写测试代码

根据我们现在的理解,测试代码不就是不断调用System.out.println(),来判断输出是否合乎预期嘛?所以可能会写成下面这种代码:

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!");
}
}

如果输出test passed!,那就代表通过测试咯~

可是...如果输出test failed!呢?那事情就很糟糕了。我们需要把每一个测试用例的结果都打印出来,看看到底是哪里出现了该死的“test failed”。本题中的测试用例很少,那如果做大的项目时有成千上万个用例呢?

不用担心!Java中有单元测试工具JUnit来辅助进行TDD,我们用TDD的方式把前面百分制转五分制的例子重写一次,体会一下有测试工具支持的开发的好处。

鼠标放在需要测试的类上单击,出现一个黄色灯泡,点击选择“Create Test”,就可以新建一个测试类啦~

那么,我们可以这么写测试代码:

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));
}
}

如果出现问题,IDEA就会提示我们具体是哪一步出错了。比如下面这个实例(我把95分的断言值改成了“良好”,我们知道测试肯定不会通过):

可以看出,IDEA提示我们Expected:良好; Actual:优秀,最后一行还有at test2.MyUtilTest.testNormal(MyUtilTest.java:11),这下我们明白了,是testNormal()方法中一个为“良好”的断言错了。这样一来,是不是比上面那种方法方便很多了呢?

当然了,测试代码不能随便一写草草了事,作为开发者的我们必须要考虑得足够周全,尤其是各种边界情况以及非法输入等等。比如本题我们需要添加testExceptions()testBoundary()等等各种方法进行测试。这些老师的教程里写得很详细,我在此就不赘述了。

任务二:以TDD的方式研究学习StringBuffer

这个任务主要锻炼我们自己写JUnit测试用例的能力。老师在教程里给出的程序如下:

public static void main(String [] args){
StringBuffer buffer = new StringBuffer();
buffer.append('S');
buffer.append("tringBuffer");
System.out.println(buffer.charAt(1));
System.out.println(buffer.capacity());
System.out.println(buffer.length());
System.out.println(buffer.indexOf("tring"));
System.out.println("buffer = " + buffer.toString());

首先我们需要对这个程序进行改写,写成上面的产品代码那种类型的,以便于我们进行测试。

对于这个程序,我们先来看一看哪些方法需要测试?有四个,charAt()capacity()length()indexOf。在产品代码里,我们需要为这四个方法加上返回值,并与我们的断言进行比较。产品代码如下:

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);
}
}

接下来我们需要对调用各种方法的返回值进行猜测。查询API文档可知,对charAt(int i)的解释为:“返回此序列中指定索引处的 char 值。第一个 char 值在索引 0 处,第二个在索引 1 处,依此类推,这类似于数组索引。”indexOf(String s)则返回输入的子字符串的第一个字母在母字符串的位置。这两个看起来都比较好理解,那capacity()length()呢?我在学习StringBuffer的时候也遇到了这样的困惑,对于这两者之间的区别问题,可以参考我博客的“问题解决”模块。

基于以上的思考和学习,我们可以对各个方法的返回值有一个精确地分析,接下来只需要比较产品代码中的方法与我们的断言值是否相等即可。

出于对老师这篇博客中问题的思考,我设置了长度不同的三个字符串进行测试,代码如下:

public class StringBufferDemoTest extends TestCase {
StringBuffer a = new StringBuffer("StringBuffer");//测试12个字符(<=16)
StringBuffer b = new StringBuffer("StringBufferStringBuffer");//测试24个字符(>16&&<=34)
StringBuffer c = new StringBuffer("StringBufferStringBufferStringBuffer");//测试36个字符(>=34)
@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"));
assertEquals(10,a.indexOf("er"));
}
}

可以看到,出现了“green bar”,说明测试通过了,我们对StringBuffer也有了更加深刻的认识。

返回目录

二、面向对象三要素:封装、继承、多态

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

任务三:使用StarUML对实验二中的代码进行建模

UML是一种通用的建模语言,可以非常直观地表现出各个结构之间的关系。

基于以上学习,我们在UML中实现了类,继承和接口的组合:

当然,UML还可以实现更多更复杂的功能,以上只是一个小小的实践。

返回目录

三、设计模式

面向对象三要素是“封装、继承、多态”,任何面向对象编程语言都会在语法上支持这三要素。如何借助抽象思维用好三要素特别是多态还是非常困难的,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类进行扩充,让其支持Long类,初步理解设计模式

OCP是OOD中最重要的一个原则,要求软件实体(类,模块,函数等)应该对扩充开放,对修改封闭。也就是说,软件模块的行为必须是可以扩充的,在应用需求改变或需要满足新的应用需求时,我们要让模块以不同的方式工作;同时,模块的源代码是不可改动的,任何人都不许修改已有模块的源代码。OCP可以用以下手段实现:(1)抽象和继承,(2)面向接口编程。

以这道题为例,已有的支持Int型的代码如下:

abstract class Data{
public abstract void DisplayValue();
}
class Integer extends Data {
int value;
Integer(){
value=100;
}
public void DisplayValue(){
System.out.println(value);
}
}
class Document {
Data pd;
Document() {
pd=new Integer();
}
public void DisplayData(){
pd.DisplayValue();
}
}
public class MyDoc {
static Document d;
public static void main(String[] args) {
d = new Document();
d.DisplayData();
}
}

如果要求支持Long类,Document类要修改构造方法,这还违反了OCP原则。封装、继承、多态解决不了问题了,这时需要设计模式了:

abstract class Data {
abstract public void DisplayValue();
}
class Integer extends Data {
int value;
Integer() {
value=100;
}
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 Long extends Dataclass LongFactory extends Factory即可使系统支持Long类型,测试代码如下:

public class MyDoc {
static Document d;
public static void main(String[] args) {
d = new Document(new LongFactory());
d.DisplayData();
}
}

我们看到,通过增加了一层抽象层使代码符合了OCP原则,使代码有良好的可扩充性、可维护性。不过,设计模式也不能过度使用,具体在哪些场合应用还要看实际问题。

返回目录

附:练习

任务五:以TDD的方式开发一个复数类Complex

经过以上的学习,我们已经可以基本熟练地应用TDD方法,并跟随TDD方法的节奏设计出伪代码、产品代码和测试代码了,这个任务算是对以上学习内容的回顾。

TDD的编码节奏是:

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

首先,我们来写伪代码:

(1)属性:复数包含实部和虚部两个部分,
double RealPart;复数的实部
double ImagePart;复数的虚部
getRealPart():返回复数的实部
getImagePart();返回复数的虚部
setRealPart():设置复数的实部
setImagePart();设置复数的虚部
输出形式:a+bi
(2)方法:
①定义构造函数
public Complex()
public Complex(double R,double I)
②定义公有方法:加减乘除
Complex ComplexAdd(Complex a):实现复数加法
Complex ComplexSub(Complex a):实现复数减法
Complex ComplexMulti(Complex a):实现复数乘法
Complex ComplexDiv(Complex a):实现复数除法
③Override Object
public String toString():将计算结果转化为字符串形式并输出

在测试代码中,我们需要对以上提到的方法进行测试。写测试代码时,如果调用了不存在的方法,可以点击这个方法旁边的小灯泡进行修复,这个操作会对应的产品代码中增加一个方法,我们只需要描述这个方法的操作即可,非常方便。

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 -3.0i", c1.ComplexMulti(c2).toString());
assertEquals("-3.0+6.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());
}
}

通过不断修复,产品代码也写好了,测试一下能不能出现“green bar”,如果测试不通过再根据提示修改产品代码。

产品代码如下:

public class Complex{
private double r;
private double i; public Complex(double r, double i) {
this.r = r;
this.i = i;
} public static double getRealPart(double r) {
return r;
} public static double getImagePart(double i) {
return i;
} public Complex ComplexAdd(Complex c) {
return new Complex(r + c.r, i + c.i);
}
public Complex ComplexSub(Complex c) {
return new Complex(r - c.r, i - c.i);
}
public Complex ComplexMulti(Complex c) {
return new Complex(r * c.r - i * c.i, r * c.i + i * c.r);
}
public Complex ComplexDiv(Complex c) {
return new Complex((r * c.i + i * c.r)/(c.i * c.i + c.r * c.r), (i * c.i + r * c.r)/(c.i * c.i + c.r * c.r));
} public String toString() {
String s = " ";
if (i > 0)
s = r + "+" + i + "i";
if (i == 0)
s = r + "";
if (i < 0)
s = r + " " + i + "i";
return s;
}
}

返回目录

四、实验过程中遇到的问题及解决

问题一:@Test或者import junit.framework.TestCase;是红色的怎么办?

我和大多数同学一样都遇到了这种情况,是因为没有导入相应的包。参考老师的教程并查阅了相关资料解决了这个问题。

解决方法如下:

首先,进入页面左上角FileProject Structure...

进入之后,根据你的IDEA安装地址导入这两个包就可以了。

问题二:如何写好一个测试单元?怎样使用各种断言方法?

本次实验我们着重学习了如何使用Junit进行单元测试,深入思考一下:单元测试中需要考虑哪些情况呢?

博客单元测试应该测试什么?——Right-BICEP对这个问题进行了较为详细的分析,大致可以总结为:

  • 结果是否正确

    这是最基本的,就是看程序运行之后的结构和文档是否一致。

  • 边界条件

    • 一致性(Conformance)——值是否符合预期的格式?
    • 有序性(Ordering)——一组值是该有序的,还是该无序的?
    • 区间性(Range)——值是否在一个合理的最大值和最小值的范围之内?
    • 引用、耦合性(Reference)——代码是否引用了一些不受代码本身直接控制的外部因素?
    • 完全伪造或者不一致的输入数据、格式错误的数据、空值或者不完整的值,如0, 0.0, “”, null之类的等等。
  • ...

在本次实验的单元测试中,我们大量使用了assertEquals()方法,来判断测试值是否与期望值相等。assertEquals()是应用非常广泛的一个断言,它的作用是比较实际的值和用户预期的值是否一样。

通过学习了解到,还可以使用assertThat(actual, matcher)方法,查看实际值是否满足指定的条件。assertThat(actual, matcher)方法可以实现一般匹配、字符串匹配、数值匹配、collection匹配等等,非常实用。

以下面这个程序为例,我随意写了几个方法,打算使用assertThat(actual, matcher)方法进行测试:

import java.util.List;
import java.util.ArrayList;
public class AssertDemo {
public int add(int a, int b) {
return a + b;
} public String getName(String name) {
return name;
} public List<String> getList(String item) {
List<String> l = new ArrayList<>();
l.add(item);
return l;
}
}

JUnit4.4引入了Hamcrest框架,Hamcest提供了一套匹配符Matcher,这些匹配符更接近自然语言,可读性高,更加灵活。不过需要注意的是,使用assertThat(actual, matcher)方法必须导入相应的类或方法:

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.matchers.JUnitMatchers.*;

得到测试代码如下:

public class AssertDemoTest {
@Test
public void testAdd() { //一般匹配符
int s = new AssertDemo().add(1, 1);
//anything:无论什么条件,测试都通过
assertThat(s, anything());
//is:变量的值等于指定值时,测试通过
assertThat(s, is(2));
//not:和is相反,变量的值不等于指定值时,测试通过
assertThat(s, not(1));
}
@Test
public void testgetName() {
//字符串匹配符
String n = new AssertDemo().getName("Magical");
//containsString:字符串变量中包含指定字符串时,测试通过
assertThat(n, containsString("ci"));
//startsWith:字符串变量以指定字符串开头时,测试通过
assertThat(n, startsWith("Ma"));
//endsWith:字符串变量以指定字符串结尾时,测试通过
assertThat(n, endsWith("l"));
//euqalTo:字符串变量等于指定字符串时,测试通过
assertThat(n, equalTo("Magical"));
}
@Test
public void testgetList(){
//集合匹配符
List<String> l = new AssertDemo().getList("Magical");
//hasItem:Iterable变量中含有指定元素时,测试通过
assertThat(l, hasItem("Magical")); }
}

JUnit框架Assert类中还有很多断言方法,比如assertTrue与assertFalse断言、assertNull与assertNotNull断言、assertSame与assertNotSame断言、fail断言等等,还有待我们进一步学习总结。

问题三:如何解决这个“red bar”?

在实验过程中遇到了这样的问题:

在测试类中定义了c1、c2和c3:

Complex c1 = new Complex(0, 3);
Complex c2 = new Complex(-1, -1);
Complex c3 = new Complex(2,1);

并测试复数的减法:

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());
}

但是测试的时候却出现了“red bar”:

检查产品代码中复数的减法也没有问题:

public Complex ComplexSub(Complex c) {
return new Complex(r - c.r, i - c.i);
}

那错误在哪里呢?

观察错误提示,断言值为-3.0 -2.0i但实际输出值为-5.0i,-5.0恰巧是-3.0 -2.0i实部和虚部的和。好像有点思路了...返回去看产品代码中的toString()方法,注意到当虚部小于零时,我直接进行了s = r + i + "i";操作,而在Java中,这个式子的含义是:先计算r + i的值,再转化为字符串形式,所以会得到错误的输出。将代码改为:s = r + " " + i + "i",先进行强制类型转换,就解决了这个问题。

问题四:Java中StringBuffer的capacity问题探究

在研究学习StringBuffer的过程中,对capacity()有疑惑,查询了API文档了解到:

从API查到capacity的作用是查看StringBuffer的容器容量是多少,刚开始纳闷这个跟length的区别在哪?

于是自己写了一个程序进行测试分析:

public class capacityDemo {
public static void main(String[] args) {
StringBuffer b = new StringBuffer();//初始分配空间为0+16
for(int i = 0; i < 50; i++){
b = b.append("A");
System.out.println(b);
System.out.print("length()="+b.length());
System.out.println("capacity()="+b.capacity());
}
}
}

打印运行结果:

可以看到,对于空字符串,调用capacity()方法初始分配值为16;大小超过16时则扩充容量为34,再次扩充得到70。

那么问题来了!16、34、70是怎么得到的呢?试验了几次还是有点不解。所以直接跟进源码分析。

直接通过new StringBuffer(String str);时,capacity是str.length+16,从源码可知:

如果小于16则默认容器的大小为16。如果大于16则会调用expandCapacity 函数进行容量的扩展,扩展方式如下:

由源码可以看到扩展的规则是把旧的容量(value的长度)*2+2,然后与现有的比较,如果小于则把现有的容量当做新的,如果大于则用新得到的容量。

所以第一次append时,小于16则不需扩展,如果大于16则会直接扩展到34(16*2+2),比较得到大于append后的长度的话则用34,如果不 是则用append后的长度。

此时capacity的大小等于append后的长度,如果在append的话,若不超过70(34*2+2)的话,此时则capacity为70,如果超过70则继续用第二次append后的总长度。

这样一来,对capacity()的理解就比较透彻了。

返回目录

五、实验体会与总结

这周的实验内容非常丰富,主要学习了如何编写测试代码。

在开发软件的过程中,用户需要实际运行所编写的代码以确保程序的正确性。当软件变得越来越大,再去添加新的功能或做一些新的改动时,就很容易带来新的问题,甚至会使程序无法正常运行。然而要手动的运行代码,测试代码的可行性也是非常枯燥以及非常耗费时间的事情。

为了减少这种手动测试,可以通过创建单元测试来自动完成测试的工作。当修改代码或者添加新功能后,可以执行单元测试来保证代码运行无误。所有测试工作都是由单元测试自动完成的,开发人员所要做的就是看看程序的执行状态。

使用单元测试的另一个理由是实现测试驱动的开发。测试驱动的开发尝试首先写出单元测试,然后完成实际的代码。通过单元测试来提供类的定义,当实际开始编写代码时,用户仅仅需要做的就是具体类的实现,只要单元测试运行通过,代码的实现也将告一段落了。写单元测试的同时,也在同时在做项目的设计,当项目结束后,单元测试还将是不错的文档,何乐而不为呢?

在Java语言中,可以通过JUnit框架进行单元测试。单元测试的实现是很简单的,可以认为它只是判断在某一个时刻,程序运行的值和预期的值是否一致,但在实际的应用的时候是很灵活的,在此介绍JUnit中的一些断言以及JUnit测试框架的使用,使读者能够快速的进入单元测试的领域,更快的进行开发。

JUnit提供了一些辅助函数,用于帮助开发人员确定某些被测试函数是否工作正常。通常而言,把所有这些函数统称为断言,断言是单元测试最基本的组成部分。

除此之外,本次实验还学习了TDD方式、UML建模、S.O.L.I.D原则以及设计模式等等,既加深了对之前内容的理解,又规范了我们的编程流程,对思维也是一个很好的梳理,希望能把这些知识在今后的学习实践中广泛应用。

步骤 耗时 百分比
需求分析 12min 10%
设计 10min 8%
代码实现 48min 40%
测试 40min 34%
分析总结 10min 8%

返回目录

六、参考资料

返回目录

20155303 实验二 Java面向对象程序设计的更多相关文章

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

    实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...

  2. 20145213《Java程序设计》实验二Java面向对象程序设计实验报告

    20145213<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装,继承,多态 初步掌握UML建模 熟悉S.O. ...

  3. 20145206《Java程序设计》实验二Java面向对象程序设计实验报告

    20145206<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O. ...

  4. 20145308刘昊阳 《Java程序设计》实验二 Java面向对象程序设计 实验报告

    20145308刘昊阳 <Java程序设计>实验二 Java面向对象程序设计 实验报告 实验名称 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面相对象三要素:封 ...

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

    20145113 实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 1.初 ...

  6. JAVA课程实验报告 实验二 Java面向对象程序设计

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计  班级:1353  姓名:韩玉琪  学号:20135317 成绩:             指导教师:娄嘉 ...

  7. 20145225唐振远 实验二 "Java面向对象程序设计"

    20145225<Java程序设计> 实验二 Java面向对象程序设计 实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S ...

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

    20145208 实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验步 ...

  9. 20162311 实验二 Java面向对象程序设计 实验报告

    实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...

随机推荐

  1. UVA10047_The Monocycle

    这题....有点奇葩,但是不难. 在矩形方阵里,某人可以往前走或者左拐右拐.都需要消耗一个单位时间. 问某人从一个点走向另一个点的最短时间,并且走过的路程是5的倍数. 由于n,m都小,直接f[n][m ...

  2. P2461 [SDOI2008]递归数列

    题目描述 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + ... + ckai-k 其中bj 和 cj ...

  3. PE文件解析 基础篇

    PE文件解析 基础篇 来源 https://bbs.pediy.com/thread-247114.htm 前言 之前学习了PE格式,为了更好的理解,决定写一个类似LoadPE的小工具. 编译器是VS ...

  4. Linux内核分析实验三----跟踪分析Linux内核的启动过程

    一.Linux内核源代码介绍 1.根目录 arch/x86目录下的代码是我们重点关注的,arch中包括支持不同CPU的源代码. init目录下包含内核启动相关的代码,如main.c(start_ker ...

  5. java多线程 -- 创建线程的第三者方式 实现Callable接口

    Java 5.0 在 java.util.concurrent 提供了一个新的创建执行线程的方式:Callable 接口Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个 ...

  6. Java EE之表达式语言EL(下)

    1.在EL表达式中使用作用域变量 表达式语言对作用域变量的支持,以及它解析变量的方式都使它变得非常有用. 1.1 EL表达式的隐式变量 EL表达式的作用域中定义了11个隐式变量. 当EL表达式引用了一 ...

  7. Google Gson用法

    the latest version is 2.8.0. If you're using Gradle, add the following line: compile 'com.google.cod ...

  8. nodejs进程异常退出处理方法

    1. 捕获uncaughtException process.on('uncaughtException', function (err) { //打印出错误 console.log(err); // ...

  9. 3532: [Sdoi2014]Lis 最小字典序最小割

    3532: [Sdoi2014]Lis Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 865  Solved: 311[Submit][Status] ...

  10. Python 个人的失误记录之str.replace

    1. replace 替换列表中元素的部分内容后返回列表 2018.06.08 错误操作 -- 这样并不能改变改变列表内的元素 data = [', '决不能回复---它'] data[2].repl ...