《重构-改善既有的代码设计》读书笔记

(一):重新组织自己的函数
 问题:过长函数(Long Method) 往往需要我们通过手法提炼函数(Extract Method),把一段代码从原函数里面提炼出一段代码放入一单独函数中。遇到的问题主要有
 临时变量问题(Temp variable matter) 和参数问题(Parameter matter),
 (1)、在处理临时变量问题时我们提供(replace temp with query)去掉一些临时变量。如果很多地方用到这个临时变量,
 可以是用Split temporary variable,将它变得容易替换,如果临时变量太乱,可以引入Replace Method with Method Object代价是引入新的class。
 (2)、处理参数使用remove Assignments to parameters。
 最后函数分解以后使用Substitute Algorithm引入更清晰的算法
 做法:在Extract Method 关键是要在函数名称和函数体之间的语义距离,强化代码的清晰度。一下是Exctract Method的三种实例
  1) 没有局部变量,直接提炼。2) 有局部变量,把这个局部变量作为参数传入被提炼函数 3)如果需要对局部变量赋值,得需要使用remove Assignments to parameters 
  如果被赋值的局部变量只在被提炼的函数中被赋值,则把这个局部变量声明到被提炼函数中。如果被赋值的局部变量需要在被提炼的函数其它的地方使用,则需要被提炼
  函数返回一个被修改后的值。如果遇到返回的不止一个值,则最好的方法是再重新提炼一个新的方法,每次只返回一个值最佳。
 (1)Inline Temp
  如果有一个临时变量,只被一个简单的表达式赋值过一次。重构手法,将所有对该变量的引用动作,替换为对它赋值的那个表达式
  double price = anOrder*basePrice();
  return price>1000
  替换=》 return anOrder*basePrice()>1000;
  (2)Replace Temp with Query
    一个临时变量保存了一个表达式的结果,需要把这个表达式提炼到一个独立函数里,在所以应用到这个临时变量的地方替换为一个新函数的调用。
     double basePrice = _quantity*_item;
     if (basePrice>1000){
      return basePrice*0.95;
     } else {
      return basePrice*0.98;
     }
     替换=》
     public  basePrice(){
      return _quantity*_item;
     }
     
     if (basePrice()>1000) {
      return basePrice*0.95
     } else {
      return basePrice*0.98;
     }
   (3) Introduce Explaining Variable
  将复杂表达式的结果放入一个临时变量里面,以此变量名来解释表达式用途
     if(platform.toUpperCase().indexOf("MSC")>-1 && browers.toUpperCase.indexOf("IE")>-1 && size()>0){...}
     替换=》
     final boolean isMSC = platform.toUpperCase().indexOf("MSC");
     final boolean isBrowsers = browers.toUpperCase.indexOf("IE");
     final boolean isResize = size()>0;
     if(isMSC && isBrowsers && isResize){...}。
     这个也可以使用Replace Temp with Query来重构
     public boolean isMSC(){retrun platform.toUpperCase().indexOf("MSC");}
     public boolean isBrowsers(){browers.toUpperCase.indexOf("IE");}
     public boolean isResize(){size()>0}
     if(isMSC() && isBrowsers() && isResize()){...}
   (4) Split Temporary Variable 解剖临时变量
    在程序中临时变量超过一次,它既不是循环变量,也不是集中临时变量。则每次给临时变量赋值,创造一个独立的,对应的临时变量
    double temp = 2*(width+height);
    System.out.println(temp);
    temp = width*height;
    System.out.println(temp);
    替换=》
    final double perimeter = 2*(width+height);
    System.out.println(perimeter);
    final double area = widht * height;
    System.out.println(area);
    final 关键字的作用是让这两个变量只被赋值一次
   (5) Remove Assignments Parameters
  对一个参数进行赋值操作,以一个临时变量来取代该参数的位置
  int disCount(int nInput, int quantity){
   if (nInput>50){
    nInput -= 2;
   }
  替换=》
  int disCount(int nInput, int quantity){
   int result = nInput;
   if (nInput>50){
    result -=2;
   } 
  }
 (6) Replace Mehtod with Method Object
  将所有的局部变量都变成函数对象(Mehtod Class)的值域(Field)。然后你就可以对这个新的对象使用Extract Method 来创造新的函数
 (7) Substitute Algorithm(替换算法)
  String findPersion(String[] persion){
   for (int i = 0; i<persion.length; i++){
    if(persion[i].equals("Don")){
     return "Don";
    }
    
    if(persion[i].equals("John")){
     return "John";
    }
    
    if(persion[i].equals("Kent")){
     return "Kent";
    }
   }
  }
  替换=》
  String findPersion(String[] persion){
   List<String> perList = Arrays.asList(new String[]{"Don","John","Kent"});
   for (int i = 0; i<persion.length; i++){
    if(perList.containts(persion[i])){
     return persion[i];
    }
   }
   return "";
  }


(二):在对象之间搬移特性
 通过Move Method 和Move Field来移动对象的行为,通常是先使用Move Field 后使用Move Method。如果class 责任太大,变得臃肿不堪,则使用
 Extract Class来分离一部分责任,如果一个类太不负责任,则使用Inline class融入到另一个类。如果一个类使用了另外一个类运用Hide Delegate
 隐藏这种关系,是很有帮助的。有时隐藏会导致Delegate Class接口拥挤,此时需要使用Remove Middle Man
 (1) Move Method
 如果这个函数使用另外一个对象的次数比使用自己所驻次数还多,则需要考虑Move Method.
 class Account{
  private AccountType accountType;
  private int daysOverdraft;
  double overdraftCharg(){
   if(accountType.isPremium()){//这个方法每次调用都需要访问accountType对象
    double result = 0l;
    if(daysOverdraft>7){
     result += (daysOverdraft -7)*0.85;
     return result;
    }
   }
   else {
    return  daysOverdraft*1.75;
   }
  }
  
  double bankCharg(){
   double result =4.5;
   if(daysOverdraft>0) {
    result +=overdraftCharg();
    return result;
   }
  }
 }
 假设有数种新帐户,每一种都有自己的透支计费规则,所有希望透支计费搬移到AccountType里去
 public class AccountType{
  double overdraftCharg(int daysOverdraft){
   if(isPremium()){
    double result = 0l;
    if(daysOverdraft>7){
     result += (daysOverdraft -7)*0.85;
     return result;
    }
   }
   else {
    return  daysOverdraft*1.75;
   }
  }
 }
 但我们在AccountType 类里面需要使用Account特性,将Account对象作为参数传递给AccountType,如果特性是个变量,只需要把这个变量当作参数传递过去
 然后我们可以删除Account里的方法,也可以保留,如果删除需要替换它在这个类其它地方的引用
 class Account{
  private AccountType accountType;
  private int daysOverdraft;
  double overdraftCharg(){
   return accountType.overdraftCharg(daysOverdraft);
  }
  
  double bankCharg(){
   double result =4.5;
   if(daysOverdraft>0) {
    result +=overdraftCharg();//或者如果已经删除了overdraftCharg() 则 result +=accountType.overdraftCharg(daysOverdraft);
    return result;
   }
  }
 } 
 
 (2) Move Field
 在程序中,某个(Field)被其所驻clss之外一个class更多的使用
 class class Account{
  private AccountType accoutType;
  private double rate;
  double cacRate(int amount, intdays){
   return rate*amount*days/365;
  }
 }
 如果rate经常被AccountType类访问,则需要移动这个Field 到这个类
 public class AccountType{
  private double rate;
  public void setRate(double rate){
   this.rate = rate;
  }
  public double getRate(){
   return rate;
  }
 }
 =》替换
 double cacRate(int amount, intdays){
   return accountType.getRate()*amount*days/365;
 }
 如果有多个函数已经使用了这个属性还需要自封装这个属性(Self Encapsulate Field)
 private void setTypeRate(rate){
  accountType.setRate(rage);
 }
 private double getTypeRate(){
  return accountType.getRate();
 }
 double cacRate(int amount, intdays){
   return  getTypeRate()*amount*days/365;
 }
 
 (3)Hide Delegate 隐藏委托关系
 在service端建立Client所有的所需函数。但有时客户端需要调用service端某个值域基础之上的函数。那么客户端必须要知道这个值域对象(Delegat Object)。
 为了达到这一目的需要隐藏委托关系。把委托关系隐藏起来,从而消除这种依存性,即使委托关系发生变化也只是在service。而不会波及Client
 public class Persion{
  Department department;
  public void setDepartment(Department department){
   this.department = department;
  }
  public Department getDepartment(){
   return department;
  }
 }
 public class Department{
  Persion Manger;
  public void setManger(Manger manger){
   this.manger = manger;
  }
  public Manger getManger(){
   return manger;
  }
 }
 
 Client: 客户想知道jack 的经理是谁?必须先取得Department
 Persion persion = new Persion("jack");
 Persion manager = persion.getDepartment().getManager();
 如果客户需要隐藏Department ,减少耦合,需要在Persion里面建立一个委托函数
 Persion 类:
 public Persion getManager(){
  return department.getManager();
 }
 客户端就可以这样调用了
 Persion manger = persion.getManager();
 
 (3)Remove Middle Man (移除中间人)
 但客户端需要使用受托类更多的新特性时,都需要在service 加入委托函数。随着新特性的增加。service就变成了中间人。解决办法是删除这些委托函数
 重新让客户端通过调用委托对象来得到新特性。
 Persion manager = persion.getDepartment().getManager();
 
 (4) Introduce Foreign Method (引入外加函数)
 如果一个service class为你提供了所有服务。但是又需要一项新的服务,而这个class 无法提供(无法修改源代码)。则需要在Client 中提供一个额外的方法,参数就是
 这个service class 实例。并且写上注释为foreign Method 本应在service class 中实现。这样一来如果要搬移这个Forign Method时候就很
 容易找到了。
 Client
 Date nextDate = new Date(previousEnd.getYear(),previousEnd.getMonth(),previousEnd.getDate()+1);
 =》替换
 public static Date nextDate(Date previousEnd){
  return new Date(previousEnd.getYear(),previousEnd.getMonth(),previousEnd.getDate()+1);
 }
 (5) Introduce Local Extension(引入本地扩展)
 如果引入外加函数太多了,就需要Introduce Local Extension,建立一个新的class 包含这些Foreign Mehtod,让这些扩展品成为source class
 的subclass(子类)或者wrapper(覆盖类)
 public class DateSub extends Date{
  //override supClass construct Method
  public DateSub(String str){
   super(str);
  }
  
  public DateSub(Date date){
   super(date.getTime());
  }
  //把外加函数都搬移过来
  //下一天
  public static Date nextDate(){
   return new Date(getYear(),getMonth(),getDate()+1);
  }
  //上一天
  public static Date PreDate(Date previousEnd){
   return new Date(getYear(),getMonth(),getDate()-1);
  }
 }
 
(三):重新组织数据
 (1) Replace Date Value with Object 以对象取代数据值
 当简单的数据项要表现复杂的行为就需要把这个数据项变成对象了。
 public class Order{
 
  private String customer;
  
  public Order(String customer){
   this.customer = customer;
  }
  
  public void SetCustomer(String customer){
   this.customer = customer;
  }
  
  public String getCustomer(){
   return this.customer;
  }
  
  public int calculateOrder(){
   int result = 0;
   for(Interator iterator = orders.iterator(); iterator.hasNext()){
    Order order = (Order)iterator.next();
    if (order.getCustomer().equals(customer)){
     result ++;
    }
   }
   return result;
  }
 }
 =》替换
 public Class Customer{
  private final String name;
  
  public Customer(String name){
   this.name = name;
  }
  
  public void SetName(String name){
   this.name = name;
  }
  
  public String getName(){
   return this.name;
  }
 }
 
 public class Order{
 
  private Customer customer;
  
  public Order(String customerName){
   this.customer = new Customer(customerName);
  }
  
  public void SetCustomer(String customerName){
   this.customer = new Customer(customerName);
  }
  
  public String getCustomerName(){
   return customer.getName();
  }
  
  public int calculateOrder(){
   int result = 0;
   for(Interator iterator = orders.iterator(); iterator.hasNext()){
    Order order = (Order)iterator.next();
    if (order.getCustomerName().equals(customer)){
     result ++;
    }
   }
   return result;
  }
 }
 这样,每个customer 作为实值对象(Value Object) 来处理,每个Order 都有一个自己的customer
 
 (2) change value to Reference (将实例对象该改为引用对象)
 这样可以使所有的order 对象共享一个customer对象。而不是每个order对象都保存一份customer对象。如果我在customer对象中加入邮政编码和其它信息
 那么对邮政编码的修改,应该会影响到所有引用此对象的地方。所以需要Reference Object。
 找出由什么样的对象来访问新对象的途径:
 a. 可能是一个静态字典(Static Dictionary)或者是注册对象(Registry Object)。
 b. 多个对象作为新对象的访问点(access point)
 以上面那个例子为例,我们希望一个客户拥有多份不同的订单。所有的order 对象都可以共享一个customer对象。
 首先要介绍一种重构方法 Replace Constructor with Method Factory
 public class Customer{
  private String name;
  
  private Customer(String name){
   this.name = name;
  }
  
  private static Map map =new HashMap();
  
  public void store(){
   map.put(name,this);
  }
  //这些对象预先创建
  private static loadCustomer(){
   new Customer("zhangsan").store();
   new Customer("wangwu").store();
   new Customer("zhaoliu").store();
  }
  //访问点
  public static Customer getInstance(String name){
   return (Customer)map.get(name);
  }
 }
 
 public class Order{
  private Customer customer;
  pulbic Order(String name){
   Customer.getInstance(name);
  }
 }
 
 Order order1 = new Order("zhangsan");
 Order order2 = new Order("zhangsan");
 无论何时得到的都是一个customer引用。如果order1,改变了customer对象的某个特征,不如电话号码,则从order2中得到的也是改变后的值
 //因为我们customer的构造函数是private ,所以不能在其它的地方Customer c = new Customer("name") 来创建对象,只能通过Mehtod Factory
 静态方法来得到这个实例这个就类似Sington Pattern。
 
 (3)Change Reference to Value 将引用对象改为实值对象
 value Object 应该是不可变的(immutable),无论何时,调用此对象的查询函数得到的都是一个结果,
 比如第一个例子中,customer作为value Object。每个order 都有自己的一份customer。
 order1.getCustomer("张三").setTelepho("123");
 order2.getCustomer("张三").getTelepho();
 如果张三开始的号码是135。order2得到的customer 的值还是135,虽然order1已经改变了张三的电话号码。
 reference Object 应该是可变的(mutable),确保某一对象修改,自动会更新其它代表某一相同事物的其它对象的修改
    要把reference Object 变成value Object 只需要重写equals()和hashCode()两个方法,并且去掉Method Factory 对构造函数的调用,
    
(4)Replace Array with Object (以对象取代数组)
    数组一般只用于以某种顺序容纳一组相似的对象,如果发现数组容纳了不同的对象,这样我们很难知道数组的第一个元素是人名还是年龄。
    此时,我们应该用对象封装起来,运用值域名称和和函数名称来传达这样的信息。
    String[] row = new String[3];
    row[0] = "张三";
 row[1] = 2;
 =》替换
 Performance p =new Performance();
 p.setName("张三");
 p.setAge(2);
 
 (5) Replace Magic Number with Symblic Constant 以符号常量或者字面常量取代魔法数。
 double potan(double mass,double height){
  return mass*9.18*height;
 }
 =》替换
 public static final GRANT_CONSTANT = 9.18;
 double potan(double mass,double height){
  return mass * GRANT_CONSTANT *height;
 }
 
 (6) Encapsulate Field(封装值域)
 public String name;
 =》替换 
 private String name;
 public String  getName(){
  return name;
 }
 public void setName(String name){
  this.name = name;
 }
 
 (7)Encapsulate Collection(封装集合)
 一般不能使用getter或者setting来得到群集或者设置群集,如果用户通过getting得到了群集,然后修改群集内容,而群集对象一无所知,所以需要
 群集对象自己提供add(),remove()方法来控制群集对象的添加和删除
 比如在学生和课程类设计中,学生和课程的关系是一对多
 在学生类里添加addCourse(),removeCourse()方法
 public class Persion{
  Map courses = new HashMap();
  
  public void addCourse(Courses course){
   courses.add(course);
  }
  
  public void addCourses(List<Courses> courses){
   courses.addAll(courses);
  }
  
  public void removeCourses(Courses course){
   courses.removeCourses(course);
  }
 }
 
 (8) Replace Subclass with Fields (以值域取代子类)
 当各个子类唯一的区别是返回常量数据的函数上,常量函数只是返回一些硬编码,可以在不同的SubClass中调用这个函数得到不同的值
 abstract class Persion{
  abstract public  boolean isMale();
  abstract public char getCode();
 }
 
 class Male extends Persion{
  public boolean isMale(){
   return true;
  }
  
  public char getCode(){
   return 'M';
  }
 }
 
 class Pemale extends Persion {
  public boolean isMale(){
   return false;
  }
  
  public char getCode(){
   return 'F';
  }
 }
 
 =》替换
 public class Persion{
     //replace construct with method factor
     private boolean arg0;
     private char arg1;
  public static Persion createMale(){
   return new Persion(true,'M');
  }
  
  public static Persion createPemale(){
   return new Persion(false,'F');
  }
  
  public Persion(boolean arg0,char arg1){
   this.arg0 = arg0;
   this.arg1 = arg1;
  }
 }
 
 //Client
 Persion persion = Persion.createMale();//male Object
 Persion persion1 = Persion.createPemale();//Pemale Object
 
(四) 简化条件表达式
 (1)Decompose Conditional(分解条件)
 把大块头代码分解成函数
 if(date.before(DATE_START) || data.after(DATE_END)){
  charge = quantity * _winterCharge * windcharge;
 } else {
  charge = quantity * sumRage;
 }
 =》替换
 private boolean noteSummber(){
  return date.before(DATE_START) || data.after(DATE_END);
 }
 
 private double winterCharge(){
  return  quantity * _winterCharge * windcharge;
 }
 
 private double sumCharge(){
  return  quantity * sumRage;
 }
 
 if(noteSummber()){
  charge = winterCharge();
 } else {
  charge = sumCharge();
 }
 
 (2)Consolidate Conditional Expression(合并条件式)
 有的时候条件检查各不相同,而结果却一致,这时可以考虑用logic-AND 或者logic-OR将条件合并为一个表达式
 double disabilityAmount(){
  if(_seriv<0) return 0;
  if(_mountDisabled<12) return 0;
  if(_isPartTime) return 0;
  //amount
  ...
 }
 =》替换 logic-OR
 boolean isNotForDisabled (){
  return ((_seriv<0) || (_mountDisabled<12) || _isPartTime);
 }
 double disabilityAmount(){
  if(isNotForDisabled ()) return 0;
  //amount
  ...
 }
 
 logic-AND 实例
 if(overs()){
  if(lengthOfService()>10){
   return 0;
  }
 }
 return 0.5;
 等价
 if(overs() && lengthOfService()>10) {
  return 0;
 } else {
  return 0.5;
 }
 
 return (overs() && lengthOfService()>10)?0:0.5;
 
 (3) Compsolidate Duplicate Conditional Fragments(合并重复的条件片段)
 有时候,如果一组条件式的所有分支都执行了所有相同的某个代码,就应该把这段代码移动到条件以外
 if(isSepcialDeal()){
  total = price * 0.95;
  send();
 } else {
  total = price * 0.98;
  send();
 }
 =》替换
 if(isSepcialDeal()){
  total = price * 0.95;
 } else {
  total = price * 0.98;
 }
 send();
 
 (4)Remove ControlFlag (移除控制标记)
 以break continue return语句代替控制标记
 void checkSecurity(String[] people){
  for (int i = 0 ;i <people.length; i++){
   boolean isFound = false;
   if(!isFound){
    if(people[i].equals("Don")){
     sendAlert();
     isFound = true;
    }
    if(people[i].equals("JOM")){
     sendAlert();
     isFound = true;
    } 
   }
  }
 }
 =》替换
 public void checkSecurity(String[] people){
  for (int i = 0 ;i <people.length; i++){
   if(people[i].equals("Don")){
    sendAlert();
    break;
   }
   if(people[i].equals("JOM")){
    sendAlert();
    break;
   } 
  }
 }
 
 return 语句返回控制标记
 public void checkSecurity(String[] people){
  String found = findScran(people);
  somerAlert(found);
 }
 
 public String findScran(String[] people){
  String found = "";
  if("".equals(found)){
   for (int i = 0 ;i <people.length; i++){
    if(people[i].equals("Don")){
     sendAlert();
     found = "Don"
    }
    if(people[i].equals("JOM")){
     sendAlert();
     found = "JOM";
    } 
   }
  }
 }
 (5) Replace Nested Conditional with Guard  clauses 以卫语句取代嵌套语句
 double getPayAmount(){
  double result;
  if(_isCount) result = deadAmount();
  else{
   if(_separated) result = separatAmount();
   else{
    if(_isRetired) result = retiredAmount();
    else{
     result = nomalAmount();
    }
   }
  }
  return result;
 }
 =》替换
 if(_isCount) reutrn deadAmount();
 if(_separated) reutrn separatAmount();
 if(_isRetired) reutrn retiredAmount()
 reutrn nomalAmount();
 条件式一般有两种,一种是所有分支都属于正常行为,另外一种是提供的答案只有一种是正常的,另外的都不正常。
 通过替换我们可以看出嵌套的if else 讲究的是一个入口和一个出口,而替换后的函数代码更清晰,只要符合条件
 了就直接返回退出,而不需要再看后面的代码。
 特例:将条件反转
 pubic double getCapital(){
  double result = 0.0;
  if(_capital>0.0){
   if(_intRate > 0.0 && _duration >0.0){
    result = (intRate/duration)*rate;
   }
  }
  return result;
 }
 =》替换
 public double getCapital(){
  double result = 0.0;
  if(_capital <=0) return result;
  if(_intRate > 0.0 && _duration >0.0){
   result = (intRate/duration)*rate;
  }
  return result;
 }
 
(五) 简化函数调用 
 (1)Separate Query form Modifier 将查询函数和修改函数分离
 如果某个函数只向你提供一个值,没有其它任何副作用(连带关系)。那么你就可以任意调用这个函数值。如果某个函数既返回对象状态值,又修改对象状态。则
 需要分离这两个函数。
 
 (2)Parameterize Method 令函数携带参数
 若干函数做了类似的工作,但在函数体中却包含不同的值,需要建立单一的函数,以参数表达那些不同的值
 Class Employee{
  public void tenPercentRaise(){
   salary*0.1;
  }
  
  public void fivePercentRaise(){
   salary*1.05;
  }
  }
  =》替换
  Class Employee{
  public void raise(double factor){
   salary*factor;
  }
  }
  
  (3) Replace Parameter with Explicit Methods 以明确的函数取代参数
  这个和Parameterize Method 正好相反
  如果某个参数有离散取值,而函数又以条件式检查这些参数,并且根据不同的参数作出不同的反应。
  public void setValue(String name,int value){
   if("weight".equals(name)){
    _weight = value;
   }
   
   if("height".equals(name)){
    _height = value;
   }
  }
  =》替换
  public void setWeight(int value){
   _weight = value;
  }
  
  public void setHeight(int value){
   _height = value;
  }
  
  (4)Preserve whole Object 保持对象完整
  有时候将来自同一个对象的若干数据项作为参数,传递给某个函数。这样做的问题,万一新的调用者需要新的数据就的修改原来的函数
  int low =dayRang.getLow();
  int high =dayRang.getHigh();
  widthPlan = plan.widthPlan(low,high);
  =》替换
  widthPlan = plan.widthPlan(dayRang);
 
 (5) Replace Parameter with Methods 以函数取代参数
 对象调用某个函数,并将结果作为传递给某个函数。而接受该参数的函数也有能力调用这个前一个函数
 int basePrice = _quantity*_itemPrice;
 disCountLevl = getDisCountLevl();
 double findPrice = disCountPrice(basePrice, disCountLevl);
 =》替换
 int basePrice = _quantity*_itemPrice;
 double findPrice = disCountPrice(basePrice);
 对getDisCountLevl()的调用在disCountPrice函数里进行。
 
 (6) Introduce Parameter Object (引入参数对象)
 某些参数总是同时出现 比如startDate endDate 以一对值表示一个范围。我们称之为数据泥团Data Clump。把这些参数组织在一起
 
 double getFlowBetween(Date startDate,Date endDate){
  .....
 }
 =》替换
 public class DateRang{
  private final Date startDate;//设置为final是只能是构造函数才能初始化
  private final Date endDate;
  
  public DateRang(Date startDate,Date endDate){
   this.startDate = startDate;
   this.endDate = endDate;
  }
  
  public Date getStartDate(){
   return startDate;
  }
  public Date getEndDate(){
   return endDate;
  }
 } 
 double getFlowBetween(DateRang dateRang){
  .....
 }
 
 (7)Replace Error Code with Exception 以异常取代错误代码
 某个函数返回一个错误的编码 -1 以表示返某种错误的情况。当一个错误发生时,并不一定要知道如何处理,只需要让调用者知道这个错误。而调用者可能将这个
 错误沿着调用链(call chain)传递下去。
 int withdraw(int amount){
  if(amount > _blance){
   return -1;
  } else {
   _blance -= amount;
   return 0;
  }
 }
 =》替换
 void withdraw(int amount) throws BalanceException{
  if(amount > _blance){
   throw new BalanceException();
  } else {
   _blance -= amount;
   return 0;
  }
 }
 
 (8) Replace Exception with Test 以测试取代异常
 面对一个调用者可以预先加一个测试条件,如果你抛出一个异常。而这个异常对你没有任何意义。
 double getValueForPeriod(int periodIndex){
  try{
   return _varArray[periodIndex];
  }catch(ArrayIndexOutOfBoundException ex){
   return 0;
  }
 }
 =》替换
 double getValueForPeriod(int periodIndex){
  if(periodIndex >=_varArray.length){ return 0; }
  return _varArray[periodIndex];
 }
 
 总结:异常只用来处理异常、罕见的行为,也就是那些产生意料子外的行为,而不能做为条件检查的替代品。

 

(8) Replace Constructor with Factory Method  以工厂函数取代构造函数

332页

(六):处理概括关系
 处理概括关系主要是将函数上下移动于继承体系之中。
(1) pull up method 函数上移
有写函数,在各个subclass中产生完全相同的结果或者函数体完全相同
比如在两个subclass中都有createBill()函数
public void createBill(Date date){
    double chargeAmount = chargeFor(Date startDate, Date endDate);
    addBill();
}

因为chargeFor()函数在每个子类中不同的结果,所以需要在superclass中
public abstract double chargeFor(Date startDate, Date endDate);
把createBill() pull up到supclass中

 

(2) pull up Constructor body 构造函数上移
你在subclass中拥有一些构造函数,它们的本体代码几乎完全相同
此时在superclass中新建一个构造函数,并在subclass构造函数中调用它
class Manager extends Employee{
   pubic Manager(String name, String id, String grade){
        this.name = name;
 this.id = id;
 this.grade = grade;
   }
}

替换=》

public class Employee{
        protected String name;
 protected String id;
 public Employee(String name,String id){
  this.name = name;
  this.id = id;
        }
}

class Manager extends Employee{
 private String grade;
 public Employee(String name, String id, String grade){
  super(name,id)
  this.grade = grade;
 }
}

 

(3) Replace Inheritance with Delegation 以委托取代继承(适配器模式的雏形)
某个subclass 只使用了subperclass接口中的一部分,或者根本就不需要继承而来的数据。
做法:在subclass中增加一个值域用以保存superclass 调整subclass函数,令它该为委托superclass,然后去掉两者之间的继承关系
比如Vector 的一个子类Statck Statck的两个方法size(),isEmpty()是从Vector继承过来的,其它两个方法push(),pop(),是Statck需要自己声明的
  class MyStatck extends Vector{
      public  void push(Object obj){
        insertElementAt(obj,0);
      }
      public Object pop(){
        Object result = firstElement();
        removeElementAt(0);
        return result;
      }
  }

替换=》

  class MyStatck extends Vector{
 Vector vector = new Vector();
 public  void pop(Object obj){
         vector.insertElementAt(obj,0);
 }
 public Object pop(){
         Object result = vector.firstElement();
         vector.removeElementAt(0);
         return result;
       }
 //这两个函数是
 public int size(){
  return vector.size();
 }
 public boolean isEmpty(){
  return vector.isEmpty();
 }
  }


(4) Replace Delegation  with Inheritance以继承取代委托
这个正好和上面Replace Inheritance with Delegation相反,如果发现自己需要使用所托类的所有函数或大部分函数,并且花费很大力气去编写极简的请托函数。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值