第9章 简化条件表达式.ppt_第1页
第9章 简化条件表达式.ppt_第2页
第9章 简化条件表达式.ppt_第3页
第9章 简化条件表达式.ppt_第4页
第9章 简化条件表达式.ppt_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、9.1 分解条件式,复杂的条件语句 从if、then、else三个段落中分别提炼出独立函数。,if (date.before(SUMMER_START) | date.after(SUMMER_END) charge = quantity * _winterRate + _winterServiceCharge; else chareg = quantity * _summerRate; if (notSummer(data) charge = winterCharge(quantity); else charge = summerCharge(quantity);,假设要计算购买某样商品的总

2、价(总价=数量单价,而这个商品在冬季和夏季的单价是不同的:,把每个分支的判断条件都提炼到一个独立函数中,如下所示:,if (date.before(SUMMER_START) | date.after(SUMMER_END) charge = quantity * _winterRate + _winterServiceCharge; else chareg = quantity * _summerRate;,if (notSummer(date) charge = winterCharge(quantity); else chareg = summerCharge(quantity); pr

3、ivate boolean notSummer(Date date) return date.before(SUMMER_START)|date.after(SUMMER_END); private double summerCharge(int quantity) return quantity * _summerRate; private double winterCharge(int quantity) return quantity * _winterRate + _winterServiceCharge; ,9.2 合并条件式,一系列条件测试,都得到相同结果 将这些测试合并为一个条件

4、式,并将这个条件式提炼成为一个独立函数。,double disablityAmount() if (_seniority 12 ) return 0; if (_isPartTime) return 0; double disabilityAmount() if (ifNotBligableForDisablility() return 0; ,确定这些条件语句都没有连带影响。 使用适当的逻辑操作符,将一系列相关条件式合并为一个。 编译,测试。 对合并后的条件式提炼函数。,连续的的条件检查,等价于一个以逻辑OR连接起来的语句:,double disablityAmount() if (_sen

5、iority 12 ) return 0; if (_isPartTime) return 0; ,double disablityAmount() if (_seniority 12 )| (_isPartTime) return 0; ,然后,在新条件式中提炼出一个独立函数,以函数名称表达该语句所检查的条件,double disabilityAmount() if (ifNotBligableForDisablility() return 0; Boolen ifNotBligableForDisablility() return (_seniority 12 )| (_isPartTim

6、e); ,9.3 合并重复的条件片段,在条件式的每个分支上有相同的一段代码。 将这段代码搬移到条件式之外。,找出执行方式不随条件变化而变化的代码: 如果这些代码位于条件式起始处,就将它移到条件式之前 如果这些代码位于条件式尾端,就将它移到条件式之后。 如果这些代码位于条件式中段,需要观察共同代码之前或之后的代码是否改变其他代码。如果有所改变,应该首先将共同代码向前或向后移动,移至条件式的起始处或尾端,再以前面所说的办法来处理。 如果代码不止一条语句,将共同代码提炼到独立函数中,再以上述方法处理。,由于条件式的两个分支都执行了send()函数,所以将该部分代码移到条件式的外围:,if (isSp

7、ecialDeal() total = price * 0.95; send(); else total = price * 0.98; send(); ,if (isSpecialDeal() total = price * 0.95; else total = price * 0.98; send();,9.4 移除控制标记,在布尔表达式中,某个变量待遇控制标记的作用 以break语句或return语句取代控制标记,方法:,找出跳出这段逻辑的控制标记值。 用break或continue代替不符合条件式的值赋予标记变量的语句。 每次并换后,编译并测试。,例:以break取代控制标记,下列函数

8、用来检杳多个人名之中是否包含两个可疑人物的名字,void checkSecurity (String people) boolean found = false; for (!found) if (peoplei.equals(don) sendAlert(); found = ture; if (peoplei.equals(john) sendAlert(); found = ture; ,很容易找出控制标记,当变量found被赋予true时,搜索就结束。为此逐一引入break语句:,void checkSecurity (String people) boolean found = fa

9、lse; for (!found) if (peoplei.equals(don) sendAlert(); break; if (peoplei.equals(john) sendAlert(); break; ,然后把对控制标记的所有引用都去掉,void checkSecurity (String people) for (int i=0; ipeople.length; i+) if (peoplei.equals(don) sendAlert(); break; if (peoplei.equals(john) sendAlert(); found = ture; ,例:以return

10、取代控制标记,本项重构的另一种方法是使用return语句。 把前面的例子稍加修改,以控制标记记录搜索结果:,变量found既是控制标记,也是运算结果。先把计算found变量的代码提炼到一个独立函数中:,void checkSecurity (String people) String found = ; for (int i=0; ipeople.length; i+) if (found.equals( ) if( people i .equals(don) sendAlert(); found = don; if (people i .equals(john) sendAlert(); f

11、ound = john; someLaterCode(found); ,void checkSecurity (String people) String found = foundMiscreant(people); someLaterCode(found); String foundMiscreant(String people) String foud = ; for(int i=0; ipeople.length; i+) if(found.equals() if(people i .equals(don) sendAlert(); found = don; if(people i .

12、equals(john) sendAlert(); found = john; return found; ,然后以return语句取代控制标记,String foundMiscreant(String people) String foud = ; for(int i=0; ipeople.length; i+) if(found.equals() if(people i .equals(don) sendAlert(); return don; if(people i .equals(john) sendAlert(); return john; return found; ,最后完全去掉

13、控制标记,String foundMiscreant(String people) for(int i=0; ipeople.length; i+) if(people i .equals(don) sendAlert(); return don; if(people i .equals(john) sendAlert(); return john; return ; ,9.5 以卫语句取代嵌套条件式,函数中的条件逻辑使人难以看清正常的执行路径 以卫语句表现所有特殊情况,如果两条分支都是正常行为,应该使用形如if.else.的条件式。 如果某个条件极其罕见,应该单独检查该条件,并在该条件为真时

14、立刻从函数中返回。这样的单独检查常常被称为卫语句。,方法 对于每个检查,放进一个卫语句。 每次将条件捡查替换成卫语句后,编译并测试。,例:薪册系统,其中以特殊规则处理死亡员工、驻外员仁、退休员工的薪资。这些情沉不常有,但的确会偶而出现,double getPayAmount() double result; if (_isDead) result = deadAmout(); else if (_isSeparated) result = separatedAmount(); else if (_isRetired) result = retiredAmount(); else result

15、= normalPayAmount(); ; return result; ,double getPayAmount() if (_isDead) return deadAmout(); if (_isSeparated) return separatedAmount(); if (_isRetired) return retiredAmount(); return normalPayAmount(); ,例:将条件逆反,public double getAdjustedCapital() double result = 0.0; if (_capital 0.0) if (_intRate

16、0.0 ,需逐一替换。在插入卫语句前,将相应的条件逆反过来。,public double getAdjustedCapital() double result = 0.0; if (_capital 0.0 ,下一个条件稍复杂,分两步进行。 首先加入“logical NOT”操作,public double getAdjustedCapital() double result = 0.0; if (_capital 0.0 ,继续简化如下:,public double getAdjustedCapital() double result = 0.0; if (_capital 0.0) ret

17、urn result; if( _intRate = 0.0 | _duration = 0.0) return result; result = (_income / _duration) * ADJ_FACTOR; return result; ,在卫语句内返回一个明确值,这样能清晰地看到卫语句返回的失败结果,public double getAdjustedCapital() double result = 0.0; if (_capital 0.0) return 0.0; if( _intRate = 0.0 | _duration = 0.0) return 0.0; result

18、 = (_income / _duration) * ADJ_FACTOR; return result; ,最后移除临时变量,public double getAdjustedCapital() double result = 0.0; if (_capital 0.0) return 0.0; if( _intRate = 0.0 | _duration = 0.0) return 0.0; return (_income / _duration) * ADJ_FACTOR; ,9.6 以多态取代条件式,条件式根据对象型别的不同而选择不同的行为 将这个条件式的每个分支放进一个子类的覆写函数

19、中,然后将原始函数声明为抽象函数,如果要处理的条件式是个更大函数中的一部分,将它提炼到独立函数。 使用移动函数方法将条件式放在继承结构的顶端 任选一个子类在其中建立一个函数,覆写子类中容纳条件式的那个函数。将与该子类相关的条件式分支复制到新建函数中,并对它进行适当调整。 编译,测试。 在子类中删掉条件式内被复制的分支 针对条件式的每个分支,重复上述过程,直到所有分支都被移到子类中的函数为止。 将子类中容纳条件式的函数声明为抽象函数。,方法:,class Employee. int payAmount ( ) swith (getType( ) ) case Employee.ENGINEER:

20、 return _monthlySalary; case Employee.SALESMAN: return _monthlySalary + _conmission; case Employee. return _monthlySalary + _bornus; default: throw new RuntimeException(incorrect employee); ,Switch语句已经被提炼出来,需将其移到EmployeeType 类中,int getType() return _type.getTypeCode(); private EmployeeType _type; ab

21、stract class EmployeeType. abstract int getTypeCode( ); class Engineer extends EmployeeType. int getTypeCode( ) return EmployeeType.ENGINEER; ,将Employee对象作为参数传递给payAmount(),修改Employee中payAmount()函数,令它委托EmployeeType:,class EmployeeType. int payAmount (Employee emp) swith (getTypeCode( ) ) case ENGINE

22、ER: return emp.getMonthlySalary(); case SALESMAN: return emp.getMonthlySalary() + emp.getConmission(); case MANAGER: return emp.getMonthlySalary() + emp.getBornus; default: throw new RuntimeException(incorrect employee); ,class Employee. int payAmount ( ) return _type.payAmount(this); ,下面开始处理switch语

23、句。首先将switch语句中的”Engineer“分支复制到Engineer类:,这个新函数覆写了父类中switch语句内处理”Engineer的分支。 重复上述过程,直到所有分支都被去除为止。,然后,将父类的payAmount()声明为抽象函数,class Employee. int payAmount (Employee emp ) return emp.getMonthlySalary(); ,class Salesman. int payAmount (Employee emp ) return emp.getMonthlySalary() + emp.getComminssion()

24、; class Manager. int payAmount (Employee emp ) return emp.getMonthlySalary() + emp.getBounus(); ,class EmployeeType. abstract int payAmount(Employee emp);,9.7 引入Null对象,某值为无效值null object 将null value替换为null object,为源类建立一个子类,使其行为像所在源类的null版本。在源类和null类加上isNull()函数,前者的isNull应该返回false,后者应该返回true。 编译。 找出所有

25、要求源对象却获得null的地方。修改它们改而获得null object。 找出所有将源对象与null做比较的地方。修改它们调用isNull()函数。 编译,测试。 找出这样的程序点:如果对象不是null,做A动作,否则做B动作。 对于每一个上述地点,在null class中覆写A动作,使其行为和B动作相同。 使用上述的被覆写动作(A),然后删除对象是否等于null的条件测试。 编译并测试,一家公用事业公司的系统以site表示地点(场所)、庭院宅第( house)和集合公寓( apartment)都使用该公司的服务。任何时候每个地点都拥有(或说都对应于)一个顾客,顾客信息以Custmer表示:,

26、Customer的其中三个特性,class Site. Customer getCustomer() return _customer; Customer _customer;,class Customer. public String getName() . public BillingPlan getPlan() . public PaymentHistory getHistory() .,系统以PaymentHistory表示顾客的付款记录,上面的各种取值函数允许客户取得各种数据。但有时候一个地点的顾客搬走了,新顾客还没搬进来,此时这个地点就没有顾客。所以必须保证Customer的所有用

27、户都能够处理“Customer对象等于nu”ll的情况。,public class PaymentHistory. int getWeeksDelingquenInLastYear(),Customer customer = site.getCustomer(); BillingPlan plan; if (customer = null) plan = BillingPlan.basic(); else plan customer.getPLan(); . String customerName; if (customer = null) customerName = occupant; e

28、lse customerName = customer.getName(); . int weekDellinquent = 0; if (customer = null)weekDellinquent = 0; else weekDellinquent = customer.getHistory().getWeekDellinquentInLastYear();,这个系统中可能使用许多Site和customer,它们都必须检查Customer对象是否等于null,这样的检查完全是重复的。 应使用null object。 首先建立一个NullCustomer,并修改Customer,使其支持对

29、象是否为Null的检查,class NullCustomer extends Customer public boolean isNull() return true; class Customer. public boolean isNull() return false; protected Customer() ,修改所有索求Customer对象的地方,使它们不返回null,而是返回一个NullCustomer对象,class Site. Customer getCustomer() return (_customer = null? Customer.newNull():_custom

30、er; ,Customer customer = site.getCustomer(); BillingPlan plan; if (customer.isNull( ) ) plan = BillingPlan.basic(); else plan customer.getPLan(); . String customerName; if (customer.isNull() ) customerName = occupant ; else customerName = customer.getName(); . int weekDellinquent = 0; if (customer.i

31、sNull() )weekDellinquent = 0; else weekDellinquent = customer.getHistory().getWeekDellinquentInLastYear();,另外修改所有使用Customer对象的地方,让它们isNull()函数进行检查,不再使用“ = null ”检查方式。,把相关行为移到NullCustomer 类中并去除条件式。首先从“取得顾客名称”开始,其原代码如下:,首先为NullCutomer加入函数,通过该函数取得顾客名称,然后去掉条件码:,以同样方法处理其他函数,使他们对相应查询作出合适的相应。,String customerName; if (customer.isNull() ) customer = occupant; else customer = customer.getName();,class NullCustomer. public String getName

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论