您的位置:首页 > 产品设计 > 产品经理

《Test-Driven development By Example》阅读(二)

2013-07-05 15:45 525 查看
第四章 变质的对象(Degenerate Objects)——使用数值对象(value object),不必担心别名问题。
1、clean code that works!
要达到这一目标,可以分步实施:先达到“that works”,在达到“clean code”。——这与“体系结构驱动开发”相反!

第五章 众生平等(Equality for All)——解决判等问题:equals()
1、三角法——或称为“间接法”
只有当例子达到2个或者更多时才对代码进行一般化。

2、存在的问题:
(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;——拟解决问题
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;

3、同步工程实践:
重写Dollar类中equals()方法:
public class Dollar {

public int amount = 0;

public Dollar(int amount) {
this.amount = amount;
}

public Dollar times(int multiplier) {
return new Dollar(amount*multiplier);
}

public boolean equals(Object object){
Dollar dollar = (Dollar)object;
return amount == dollar.amount;
}
}

对equals()方法书写测试代码:

public class testDollar extends TestCase {
public void testMultiplication(){
Dollar five = new Dollar(5);
Dollar product = five.times(2);
assertEquals(10,product.amount);
product=five.times(3);
assertEquals(15,product.amount);
}

public void testEquality(){
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
}
}

测试通过,消除问题(6)。

第六章 私有性(privacy)——把公有变成私有

1、存在的问题:
(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;——待解决问题
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;

2、同步工程实践:

对原有测试代码进行调整,引入内联(inline)语句:
(1)去除原来的product对象,同时消除了product对amount的引用;
(2)让对象之间进行比较;

public class testDollar extends TestCase {
public void testMultiplication(){
Dollar five = new Dollar(5);
assertEquals(new Dollar(10),five.times(2));
assertEquals(new Dollar(15),five.times(3));
}

public void testEquality(){
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
}
}

经过修改,现在Dollar类是唯一个使用实例变量amount的类,可以把amount设为private。
修改Dollar类代码:

public class Dollar {

private int amount = 0;

public Dollar(int amount) {
this.amount = amount;
}

public Dollar times(int multiplier) {
return new Dollar(amount*multiplier);
}

public boolean equals(Object object){
Dollar dollar = (Dollar)object;
return amount == dollar.amount;
}
}

若直接修改Dollar类amount为私有,不进行测试代码修改,则会出错:
java中访问私有变量只能使用getter()和setter()!





第七章 法郎在诉说(Franc-ly Speaking)——处理法郎问题

1、存在的问题:

(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;——待解决问题

2、同步工程实践:

建立同dollar一样的类以及方法:

public class Franc {

private int amount = 0;

public Franc(int amount) {
this.amount = amount;
}

public Franc times(int multiplier) {
return new Franc(amount*multiplier);
}

public boolean equals(Object object){
Franc dollar = (Franc)object;
return amount == dollar.amount;
}
}
这样就完成了问题(10),但同时新增加了三个问题!
(11)Dollar与Franc之间的重复设计问题;
(12)普通判等;
(13)普通相乘;

第八章 再议众生平等(Equality for All:Redux)——解决判等问题

1、存在的问题:

(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;

(11)Dollar与Franc之间的重复设计问题;
(12)普通判等;——待解决问题
(13)普通相乘;

2、同步工程实践:

(1)抽取父类Money,使Dollar和Franc都继承Money;
(2)把子类公共代码抽取到父类;——在父类Money中声明amount为protected,以便子类能够看到。
(3)把equals()方法上移到父类中;

父类Money代码如下:
public class Money {

protected int amount = 0;

public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount;
}
}

子类Franc代码如下:

public class Franc extends Money{

public Franc(int amount) {
this.amount = amount;
}

public Franc times(int multiplier) {
return new Franc(amount*multiplier);
}
}

子类Dollar代码如下:
public class Dollar extends Money{

public Dollar(int amount) {
this.amount = amount;
}

public Dollar times(int multiplier) {
return new Dollar(amount*multiplier);
}
}

测试代码不作任何变化:

public class testDollar extends TestCase {
public void testMultiplication(){
Dollar five = new Dollar(5);
assertEquals(new Dollar(10),five.times(2));
assertEquals(new Dollar(15),five.times(3));
}

public void testEquality(){
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
}
}

第九章 苹果和橘子(Apples and Oranges)——两个对象的判等问题(数值和类均相等时才相等)

1、存在的问题:

(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;

(11)Dollar与Franc之间的重复设计问题;
(12)普通判等;
(13)普通相乘;

2、同步工程实践:

(1)进一步修改测试代码,比较Dollar和Franc两个对象

public class testDollar extends TestCase {
public void testMultiplication(){
Dollar five = new Dollar(5);
assertEquals(new Dollar(10),five.times(2));
assertEquals(new Dollar(15),five.times(3));
}

public void testEquality(){
assertTrue(new Dollar(5).equals(new Dollar(5)));
assertFalse(new Dollar(5).equals(new Dollar(6)));
assertTrue(new Franc(5).equals(new Franc(5)));
assertFalse(new Franc(5).equals(new Franc(6)));

assertFalse(new Franc(5).equals(new Dollar(5)));
}
}
测试失败!——表明当前的对象比较还存在问题!
新引入问题:
(14)对象之间的判等;
(15)货币表示?

(2)继续修改equals()代码,并进行断点调试,结果如下:

public class Money {

protected int amount = 0;

public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount
&& getClass().equals(money.getClass());
}
}





分析语句assertFalse(new Franc(5).equals(new Dollar(5))):
其中new Franc(5).equals()中equals()调用继承自父类Money的方法,其中getClass()返回值为Franc实例的类型Franc;而参数中money.getClass()返回的是Dollar实例的类型类Dollar。

第十章 制造对象(Makin' Objects)——使用工厂方法制造对象

1、存在的问题:

(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;

(11)Dollar与Franc之间的重复设计问题;
(12)普通判等;
(13)普通相乘;

(14)对象之间的判等;
(15)货币表示?

2、同步工程实践:

(1)主要是对两个子类中极为相似的times()函数进行修改;

修改后的Money类:
public abstract class Money {

protected int amount = 0;

public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount
&& getClass().equals(money.getClass());
}

public static Dollar dollar(int amount) {
return new Dollar(amount);
}

public static Franc franc(int amount) {
return new Franc(amount);
}

public abstract Money times(int multiplier);
}

修改后的Dollar类和Franc类:

public class Dollar extends Money{

public Dollar(int amount) {
this.amount = amount;
}

public Money times(int multiplier) {
return new Dollar(amount*multiplier);
}
}

public class Franc extends Money{

public Franc(int amount) {
this.amount = amount;
}

public Money times(int multiplier) {
return new Franc(amount*multiplier);
}
}

修改后的测试代码:
public class testDollar extends TestCase {
public void testMultiplication(){
Money five = Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}

public void testEquality(){
assertTrue(Money.dollar(5).equals(new Dollar(5)));
assertFalse(Money.dollar(5).equals(new Dollar(6)));
assertTrue(Money.franc(5).equals(new Franc(5)));
assertFalse(Money.franc(5).equals(new Franc(6)));

assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
}

下一步消除times()的重复设计!

第十一章 我们所处的时代(Times we are live in)——消除times()重复设计!

1、存在的问题:

(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;

(11)Dollar与Franc之间的重复设计问题;
(12)普通判等;
(13)普通相乘;

(14)对象之间的判等;
(15)货币表示?

2、同步工程实践:
(1)增加货币属性;

public abstract class Money {

protected int amount = 0;
protected String currancy;

public Money(int amount, String currancy) {
this.amount = amount;
this.currancy = currancy;
}

public static Dollar dollar(int amount) {
return new Dollar(amount,"USD");
}

public static Franc franc(int amount) {
return new Franc(amount,"CHF");
}

public abstract Money times(int multiplier);

public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount
&& getClass().equals(money.getClass());
}

public String currancy(){
return currancy;
}
}

public class Franc extends Money{

public Franc(int amount, String currancy) {
super(amount, currancy);
}

public Money times(int multiplier) {
return Money.franc(amount*multiplier);
}
}

public class Dollar extends Money{

public Dollar(int amount, String currancy) {
super(amount,currancy);
}

public Money times(int multiplier) {
return Money.dollar(amount*multiplier);
}
}

public class testDollar extends TestCase {
public void testMultiplication(){
Money five = Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}

public void testCurrancy(){
assertEquals("USD",Money.dollar(1).currancy());
assertEquals("CHF",Money.franc(1).currancy());
}
}

第十二章 有趣的Times方法(Interesting Times)——消除times()重复设计!

1、存在的问题:

(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(2)5美元 * 2 = 10美元;
(3)将amount定义为私有;
(4)Dollar类有副作用吗?
(5)钱数为整数;
(6)实现equals()函数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;

(11)Dollar与Franc之间的重复设计问题;
(12)普通判等;
(13)普通相乘;

(14)对象之间的判等;
(15)货币表示?

2、同步工程实践:
提取times方法到父类中:

public class Money {

protected int amount = 0;
protected String currancy;

public Money(int amount, String currancy) {
this.amount = amount;
this.currancy = currancy;
}

public static Dollar dollar(int amount) {
return new Dollar(amount,"USD");
}

public static Franc franc(int amount) {
return new Franc(amount,"CHF");
}

public Money times(int multiplier){
return new Money(amount*multiplier,currancy);
}

public boolean equals(Object object){
Money money = (Money)object;
return amount == money.amount
&& this.currancy.equals(money.currancy());
}

public String currancy(){
return currancy;
}

}

public class Franc extends Money{

public Franc(int amount, String currancy) {
super(amount, currancy);
}
}

public class Dollar extends Money{

public Dollar(int amount, String currancy) {
super(amount,currancy);
}
}

public class testDollar extends TestCase {
public void testMultiplication(){
Money five = Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}

public void testCurrancy(){
assertEquals("USD",Money.dollar(1).currancy());
assertEquals("CHF",Money.franc(1).currancy());
}

}
测试通过!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: