第四章 变质的对象(Degenerate Objects)——使用数值对象(value object),不必担心别名问题。
1、clean code that works!
要达到这一目标,可以分步实施:
先达到“that works”,在达到“clean code”。——这与“体系结构驱动开发”相反!
3、同步工程实践:
重写Dollar类中equals()方法:
publicclassDollar{
publicintamount=0;
publicDollar(intamount){
this.amount=amount;
}
publicDollartimes(intmultiplier){
returnnewDollar(amount*multiplier);
}
publicbooleanequals(Objectobject){
Dollardollar=(Dollar)object;
returnamount==dollar.amount;
}
}
publicclasstestDollarextendsTestCase{
publicvoidtestMultiplication(){
Dollarfive=newDollar(5);
Dollarproduct=five.times(2);
assertEquals(10,product.amount);
product=five.times(3);
assertEquals(15,product.amount);
}
publicvoidtestEquality(){
assertTrue(newDollar(5).equals(newDollar(5)));
assertFalse(newDollar(5).equals(newDollar(6)));
}
}
测试通过,消除问题(6)。
第六章 私有性(privacy)——把公有变成私有
1、存在的问题:
(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(3)将amount定义为私有;——待解决问题
(5)钱数为整数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(10)5法郎 * 2 = 10法郎;
2、同步工程实践:
对原有测试代码进行调整,引入内联(inline)语句:
(1)去除原来的product对象,同时消除了product对amount的引用;
(2)让对象之间进行比较;
publicclasstestDollarextendsTestCase{
publicvoidtestMultiplication(){
Dollarfive=newDollar(5);
assertEquals(newDollar(10),five.times(2));
assertEquals(newDollar(15),five.times(3));
}
publicvoidtestEquality(){
assertTrue(newDollar(5).equals(newDollar(5)));
assertFalse(newDollar(5).equals(newDollar(6)));
}
}
经过修改,现在Dollar类是唯一个使用实例变量amount的类,可以把amount
设为private。
publicclassDollar{
privateintamount=0;
publicDollar(intamount){
this.amount=amount;
}
publicDollartimes(intmultiplier){
returnnewDollar(amount*multiplier);
}
publicbooleanequals(Objectobject){
Dollardollar=(Dollar)object;
returnamount==dollar.amount;
}
}
java中访问私有变量只能使用getter()和setter()!
第七章 法郎在诉说(Franc-ly Speaking)——处理法郎问题
1、存在的问题:
建立同dollar一样的类以及方法:
publicclassFranc{
privateintamount=0;
publicFranc(intamount){
this.amount=amount;
}
publicFranctimes(intmultiplier){
returnnewFranc(amount*multiplier);
}
publicbooleanequals(Objectobject){
Francdollar=(Franc)object;
returnamount==dollar.amount;
}
}
这样就完成了问题(10),但同时新增加了三个问题!
(11)Dollar与Franc之间的重复设计问题;
(12)普通判等;
(13)普通相乘;
第八章 再议众生平等(Equality for All:Redux)——解决判等问题
(1)抽取父类Money,使Dollar和Franc都继承Money;
publicclassMoney{
protectedintamount=0;
publicbooleanequals(Objectobject){
Moneymoney=(Money)object;
returnamount==money.amount;
}
}
子类Franc代码如下:
publicclassFrancextendsMoney{
publicFranc(intamount){
this.amount=amount;
}
publicFranctimes(intmultiplier){
returnnewFranc(amount*multiplier);
}
}
子类Dollar代码如下:
publicclassDollarextendsMoney{
publicDollar(intamount){
this.amount=amount;
}
publicDollartimes(intmultiplier){
returnnewDollar(amount*multiplier);
}
}
测试代码不作任何变化:
publicclasstestDollarextendsTestCase{
publicvoidtestMultiplication(){
Dollarfive=newDollar(5);
assertEquals(newDollar(10),five.times(3));
}
publicvoidtestEquality(){
assertTrue(newDollar(5).equals(newDollar(5)));
assertFalse(newDollar(5).equals(newDollar(6)));
}
}
第九章 苹果和橘子(Apples and Oranges)——两个对象的判等问题(数值和类均相等时才相等)
publicclasstestDollarextendsTestCase{
publicvoidtestMultiplication(){
Dollarfive=newDollar(5);
assertEquals(newDollar(10),five.times(3));
}
publicvoidtestEquality(){
assertTrue(newDollar(5).equals(newDollar(5)));
assertFalse(newDollar(5).equals(newDollar(6)));
assertTrue(newFranc(5).equals(newFranc(5)));
assertFalse(newFranc(5).equals(newFranc(6)));
assertFalse(newFranc(5).equals(newDollar(5)));
}
}
测试失败!——表明当前的对象比较还存在问题!
新引入问题:
(14)对象之间的判等;
(15)货币表示?
publicclassMoney{
protectedintamount=0;
publicbooleanequals(Objectobject){
Moneymoney=(Money)object;
returnamount==money.amount
&&getClass().equals(money.getClass());
}
}
分析语句
assertFalse(newFranc(5).equals(newDollar(5))):
其中
newFranc(5).equals()中equals()调用继承自父类Money的方法,其中getClass()返回值为Franc实例的类型Franc;而参数中money.getClass()返回的是Dollar实例的类型类Dollar。
第十章 制造对象(Makin' Objects)——使用工厂方法制造对象
修改后的Money类:
publicabstractclassMoney{
protectedintamount=0;
publicbooleanequals(Objectobject){
Moneymoney=(Money)object;
returnamount==money.amount
&&getClass().equals(money.getClass());
}
publicstaticDollardollar(intamount){
returnnewDollar(amount);
}
publicstaticFrancfranc(intamount){
returnnewFranc(amount);
}
publicabstractMoneytimes(intmultiplier);
}
修改后的Dollar类和Franc类:
publicclassDollarextendsMoney{
publicDollar(intamount){
this.amount=amount;
}
publicMoneytimes(intmultiplier){
returnnewDollar(amount*multiplier);
}
}
publicclassFrancextendsMoney{
publicFranc(intamount){
this.amount=amount;
}
publicMoneytimes(intmultiplier){
returnnewFranc(amount*multiplier);
}
}
publicclasstestDollarextendsTestCase{
publicvoidtestMultiplication(){
Moneyfive=Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}
publicvoidtestEquality(){
assertTrue(Money.dollar(5).equals(newDollar(5)));
assertFalse(Money.dollar(5).equals(newDollar(6)));
assertTrue(Money.franc(5).equals(newFranc(5)));
assertFalse(Money.franc(5).equals(newFranc(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5)));
}
}
下一步消除times()的重复设计!
第十一章 我们所处的时代(Times we are live in)——消除times()重复设计!
publicabstractclassMoney{
protectedintamount=0;
protectedStringcurrancy;
publicMoney(intamount,Stringcurrancy){
this.amount=amount;
this.currancy=currancy;
}
publicstaticDollardollar(intamount){
returnnewDollar(amount,"USD");
}
publicstaticFrancfranc(intamount){
returnnewFranc(amount,"CHF");
}
publicabstractMoneytimes(intmultiplier);
publicbooleanequals(Objectobject){
Moneymoney=(Money)object;
returnamount==money.amount
&&getClass().equals(money.getClass());
}
publicStringcurrancy(){
returncurrancy;
}
}
publicclassFrancextendsMoney{
publicFranc(intamount,Stringcurrancy){
super(amount,currancy);
}
publicMoneytimes(intmultiplier){
returnMoney.franc(amount*multiplier);
}
}
publicclassDollarextendsMoney{
publicDollar(intamount,currancy);
}
publicMoneytimes(intmultiplier){
returnMoney.dollar(amount*multiplier);
}
}
publicclasstestDollarextendsTestCase{
publicvoidtestMultiplication(){
Moneyfive=Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}
publicvoidtestCurrancy(){
assertEquals("USD",Money.dollar(1).currancy());
assertEquals("CHF",Money.franc(1).currancy());
}
}
第十二章 有趣的Times方法(Interesting Times)——消除times()重复设计!
1、存在的问题:
(1)汇率转换问题,当汇率为2:1时,5美元 + 10法郎 = 10美元;
(5)钱数为整数;
(7)实现hashCode()函数;
(8)与空对象判等;
(9)与非同类对象判等;
(11)Dollar与Franc之间的重复设计问题;
2、同步工程实践:
publicclassMoney{
protectedintamount=0;
protectedStringcurrancy;
publicMoney(intamount,Stringcurrancy){
this.amount=amount;
this.currancy=currancy;
}
publicstaticDollardollar(intamount){
returnnewDollar(amount,"USD");
}
publicstaticFrancfranc(intamount){
returnnewFranc(amount,"CHF");
}
publicMoneytimes(intmultiplier){
returnnewMoney(amount*multiplier,currancy);
}
publicbooleanequals(Objectobject){
Moneymoney=(Money)object;
returnamount==money.amount
&&this.currancy.equals(money.currancy());
}
publicStringcurrancy(){
returncurrancy;
}
}
publicclassFrancextendsMoney{
publicFranc(intamount,Stringcurrancy){
super(amount,currancy);
}
}
publicclassDollarextendsMoney{
publicDollar(intamount,currancy);
}
}
publicclasstestDollarextendsTestCase{
publicvoidtestMultiplication(){
Moneyfive=Money.dollar(5);
assertEquals(Money.dollar(10),five.times(2));
assertEquals(Money.dollar(15),five.times(3));
}
publicvoidtestCurrancy(){
assertEquals("USD",Money.dollar(1).currancy());
assertEquals("CHF",Money.franc(1).currancy());
}
测试通过!