《重构》 — Java示例:影片出租店程序(3、重构——分解并重组Statement)

    技术2022-05-20  42

    示例:影片出租店程序(重构——分解并重组Statement) 步骤: 1、提炼“金额计算”代码 1.1、提炼“逻辑泥团”——“提炼方法(Extract Method)” Statement()中一个明显的“逻辑泥团”就是switch语句,把它提炼到独立函数“AmountFor”中。 Eclipse工具重构步骤: (1)、选中代码   (2)、右键选择“Extract Method”   (3)、输入方法名“amountFor”   (4)、调整代码如下     public String statement() {         double totalAmount = 0; //--总消费金额         int frequentRenterPoints = 0; //--常客积点         Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             double thisAmount = 0;             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                          thisAmount = amountFor(each);                          //---累加常客积点             frequentRenterPoints ++;             if (each.get_movie().get_priceCode() == Movie.NEW_RELEASE &&                 each.get_daysRented() > 1)                 frequentRenterPoints ++;             //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(thisAmount) + "/n";             totalAmount += thisAmount;         }         //---结尾打印         result += "Amount owed is " + String.valueOf(totalAmount) + "/n";         result += "You earned " + String.valueOf(frequentRenterPoints) +                  " frequent renter points";         return result;     }     private double amountFor(Rental each) {     //--计算一笔租片费用         double thisAmount = 0;                  switch(each.get_movie().get_priceCode()){  //--取得影片出租价格             case Movie.REGULAR: //--普通片                 thisAmount += 2;                 if (each.get_daysRented() > 2)                     thisAmount += (each.get_daysRented() - 2) * 1.5;                 break;             case Movie.NEW_RELEASE:  //--新片                 thisAmount += each.get_daysRented() * 3;                 break;             case Movie.CHILDRENS: //--儿童片                 thisAmount += 1.5;                 if (each.get_daysRented() > 3)                     thisAmount += (each.get_daysRented() - 3) * 1.5;                 break;         }                  return thisAmount;     } 1.2、规范变量名称 好的代码应该清楚表达出自己的功能,变量名称是代码清浙的关键。 Eclipse工具重构步骤: (1)、选中“变量名称” (2)、右键选中“Rename”   (3)、输入新的“变量名称”   (4)、调整代码如下     private double amountFor(Rental aRental) {    //--计算一笔租片费用         double result = 0;                  switch(aRental.get_movie().get_priceCode()){  //--取得影片出租价格             case Movie.REGULAR: //--普通片                 result += 2;                 if (aRental.get_daysRented() > 2)                     result += (aRental.get_daysRented() - 2) * 1.5;                 break;             case Movie.NEW_RELEASE:  //--新片                 result += aRental.get_daysRented() * 3;                 break;             case Movie.CHILDRENS: //--儿童片                 result += 1.5;                 if (aRental.get_daysRented() > 3)                     result += (aRental.get_daysRented() - 3) * 1.5;                 break;         }                  return result;     } 1.3、搬移“金额计算”代码——“搬移方法(Move Method)” AmountFor函数使用了来自Rental类的信息.却没有使用来自Customer类的信息。这表明它可能是被放错了位置,应将AmountFor()移到Rental类中。此外,还要在搬移的同时变更函数名称(AmountFor –> GetCharge)。 Eclipse工具重构步骤: 1、搬移方法 (1)、选中“方法名称” (2)、右键选择“Move”   (3)、搬移方法   (4)、调整代码如下 package Movie_Ref; /** * 租赁 * */ public class Rental {     private Movie _movie; //影片     private int _daysRented; //租期          public Rental(Movie movie, int daysRented) {         _movie = movie;         _daysRented = daysRented;     }     public int get_daysRented() {         return _daysRented;     }     public Movie get_movie() {         return _movie;     }     double amountFor() {    //--计算一笔租片费用         double result = 0;                  switch(get_movie().get_priceCode()){  //--取得影片出租价格             case Movie.REGULAR: //--普通片                 result += 2;                 if (get_daysRented() > 2)                     result += (get_daysRented() - 2) * 1.5;                 break;             case Movie.NEW_RELEASE:  //--新片                 result += get_daysRented() * 3;                 break;             case Movie.CHILDRENS: //--儿童片                 result += 1.5;                 if (get_daysRented() > 3)                     result += (get_daysRented() - 3) * 1.5;                 break;         }                  return result;     } } 2、变更函数名称 (1)、选中“函数名称” (2)、右键选中“Rename”   (3)、输入新的“函数名称”   (4)、调整代码如下     double getCharge() {    //--计算一笔租片费用         double result = 0;                  switch(get_movie().get_priceCode()){  //--取得影片出租价格             case Movie.REGULAR: //--普通片                 result += 2;                 if (get_daysRented() > 2)                     result += (get_daysRented() - 2) * 1.5;                 break;             case Movie.NEW_RELEASE:  //--新片                 result += get_daysRented() * 3;                 break;             case Movie.CHILDRENS: //--儿童片                 result += 1.5;                 if (get_daysRented() > 3)                     result += (get_daysRented() - 3) * 1.5;                 break;         }                  return result;     } 1.4、删除临时变量——“替换临时变量(Replace Temp with Query)” Statement方法中的临时变量thisAmount接受each.GetCharge的执行结果,然后就不再有任何改变。所以尽量除去这一类临时变量。     public String statement() {         double totalAmount = 0; //--总消费金额         int frequentRenterPoints = 0; //--常客积点         Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                                      //---累加常客积点             frequentRenterPoints ++;             if (each.get_movie().get_priceCode() == Movie.NEW_RELEASE &&                 each.get_daysRented() > 1)                 frequentRenterPoints ++;             //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(each.getCharge()) + "/n";             totalAmount += each.getCharge();         }         //---结尾打印         result += "Amount owed is " + String.valueOf(totalAmount) + "/n";         result += "You earned " + String.valueOf(frequentRenterPoints) +                  " frequent renter points";         return result;     } 2、提炼“常客积点计算”代码 2.1、提炼“常客积点计算”代码——“提炼函数(Extract Method)” 首先,我们需要针对“常客积点计算”这部分代码运用“提炼函数(Extract Method)”重构准则,将其提炼为函数“GetFrequentRenterPoints”。     public String statement() {         double totalAmount = 0; //--总消费金额         int frequentRenterPoints = 0; //--常客积点         Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                                      //---累加常客积点             frequentRenterPoints = getFrequentRenterPoints(frequentRenterPoints, each);             //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(each.getCharge()) + "/n";             totalAmount += each.getCharge();         }         //---结尾打印         result += "Amount owed is " + String.valueOf(totalAmount) + "/n";         result += "You earned " + String.valueOf(frequentRenterPoints) +                  " frequent renter points";         return result;     }     private int getFrequentRenterPoints(int frequentRenterPoints, Rental each) {         frequentRenterPoints ++;         if (each.get_movie().get_priceCode() == Movie.NEW_RELEASE &&             each.get_daysRented() > 1)             frequentRenterPoints ++;                  return frequentRenterPoints;     } 然后,在“GetFrequentRenterPoints”函数内找到局部变量each,它可以被当作参数传入新函数中。另一个临时变量是frequentRenterPoints。本例中的它在被使用之前已经先有初值,但提炼出来的函数并没有读取该值,所以我们不需要将它当作参数传进去,只需对它执行“追加赋值操作“就行 。     public String statement() {         double totalAmount = 0; //--总消费金额         int frequentRenterPoints = 0; //--常客积点         Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                                      //---累加常客积点             frequentRenterPoints += getFrequentRenterPoints(each);             //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(each.getCharge()) + "/n";             totalAmount += each.getCharge();         }         //---结尾打印         result += "Amount owed is " + String.valueOf(totalAmount) + "/n";         result += "You earned " + String.valueOf(frequentRenterPoints) +                  " frequent renter points";         return result;     }     private int getFrequentRenterPoints(Rental each) {         int frequentRenterPoints = 0; //--常客积点                          if (each.get_movie().get_priceCode() == Movie.NEW_RELEASE &&             each.get_daysRented() > 1)             frequentRenterPoints = 2;         else             frequentRenterPoints = 1;                  return frequentRenterPoints;     } 2.2、规范变量名称     private int getFrequentRenterPoints(Rental each) {         if (each.get_movie().get_priceCode() == Movie.NEW_RELEASE &&             each.get_daysRented() > 1)             return 2;         else             return 1;     } 2.3、搬移“常客积点计算”代码——“搬移方法(Move Method)” public class Customer {     …………          public String statement() {         double totalAmount = 0; //--总消费金额         int frequentRenterPoints = 0; //--常客积点         Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                                      //---累加常客积点             frequentRenterPoints += each.getFrequentRenterPoints();             //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(each.getCharge()) + "/n";             totalAmount += each.getCharge();         }         //---结尾打印         result += "Amount owed is " + String.valueOf(totalAmount) + "/n";         result += "You earned " + String.valueOf(frequentRenterPoints) +                  " frequent renter points";         return result;     } } public class Rental {     …………     int getFrequentRenterPoints() {         if (get_movie().get_priceCode() == Movie.NEW_RELEASE &&             get_daysRented() > 1)             return 2;         else             return 1;     } } 3、总量计算(去除临时变量) statement函数中有两个临时变量totalAmount和frequentRenterPoints,两者都是用来从Customer对象相关的Rental对象中获得某个总量。因为不论 ASCll 版或 HTML 版都需要这些总量。所以,我们运用“替换临时变量(Replace Temp with Query)”和“查询方法(Query Method)”来取代临时变量。 通过去除临时变量,可以将冗长复杂的函数中的逻辑理顺,并使其更为清晰。如果系统中的其它地方需要这些信息,也可以很轻松地将“查询方法”加入Customer类的公共接口。  3.1、总消费金额 首先,使用“查询方法GetTotalCharge”去除“临时变量totalAmount”。     private double getTotalCharge() {         double totalAmount = 0; //--总消费金额                 Enumeration rentals = _rentals.elements();                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录             totalAmount += each.getCharge();         }                          return totalAmount;     } 然后规范getTotalCharge方法中变量名称。 public class Customer {     …………          public String statement() {                 int frequentRenterPoints = 0; //--常客积点         Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                                      //---累加常客积点             frequentRenterPoints += each.getFrequentRenterPoints();             //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(each.getCharge()) + "/n";         }         //---结尾打印         result += "Amount owed is " + String.valueOf(getTotalCharge()) + "/n";         result += "You earned " + String.valueOf(frequentRenterPoints) +                  " frequent renter points";         return result;     }     private double getTotalCharge() {         double result = 0; //--总消费金额                 Enumeration rentals = _rentals.elements();                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录             result += each.getCharge();         }                          return result;     } } 3.2、总常客积点 首先,用“查询方法GetTotalFrequentRenterPoints”去除“临时变量frequentRenterPoints”。     private int getTotalFrequentRenterPoints() {         int frequentRenterPoints = 0; //--常客积点                 Enumeration rentals = _rentals.elements();                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                     //---累加常客积点             frequentRenterPoints += each.getFrequentRenterPoints();         }                  return frequentRenterPoints;     } 然后规范GetTotalFrequentRenterPoints方法中变量名称。 public class Customer {     …………          public String statement() {                 Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                                     //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(each.getCharge()) + "/n";         }         //---结尾打印         result += "Amount owed is " + String.valueOf(getTotalCharge()) + "/n";         result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) +                  " frequent renter points";         return result;     }     private int getTotalFrequentRenterPoints() {         int result = 0; //--常客积点                 Enumeration rentals = _rentals.elements();                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                     //---累加常客积点             result += each.getFrequentRenterPoints();         }                  return result;     }     ………… } 代码: 1、Customer.java package Movie_Ref; import java.util.Enumeration; import java.util.Vector; public class Customer {     private String _name;//姓名     private Vector _rentals = new Vector(); //租借记录          public Customer(String name) {         _name = name;     }     public void addRental(Rental obj) {         _rentals.addElement(obj);     }     public String get_name() {         return _name;     }          public String statement() {                 Enumeration rentals = _rentals.elements();         String result = "Rental Record for " + get_name() + "/n";                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                                     //---显示此笔租借数据             result += "/t" + each.get_movie().get_title() + "/t" +                        String.valueOf(each.getCharge()) + "/n";         }         //---结尾打印         result += "Amount owed is " + String.valueOf(getTotalCharge()) + "/n";         result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) +                  " frequent renter points";         return result;     }     private int getTotalFrequentRenterPoints() {         int result = 0; //--常客积点                 Enumeration rentals = _rentals.elements();                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录                     //---累加常客积点             result += each.getFrequentRenterPoints();         }                  return result;     }     private double getTotalCharge() {         double result = 0; //--总消费金额                 Enumeration rentals = _rentals.elements();                  while(rentals.hasMoreElements()){             Rental each = (Rental) rentals.nextElement(); //--取得一笔租借记录             result += each.getCharge();         }                          return result;     }     } 2、Movie.java package Movie_Ref; /** * 影片 * */ public class Movie {     public static final int REGULAR = 0;     public static final int NEW_RELEASE = 1;     public static final int CHILDRENS = 2;          private String _title; //名称     private int _priceCode; //价格(代号)          public Movie(String title, int priceCode) {         _title = title;         _priceCode = priceCode;     }     public int get_priceCode() {         return _priceCode;     }     public void set_priceCode(int code) {         _priceCode = code;     }     public String get_title() {         return _title;     }      } 3、Rental.java package Movie_Ref; /** * 租赁 * */ public class Rental {     private Movie _movie; //影片     private int _daysRented; //租期          public Rental(Movie movie, int daysRented) {         _movie = movie;         _daysRented = daysRented;     }     public int get_daysRented() {         return _daysRented;     }     public Movie get_movie() {         return _movie;     }     double getCharge() {    //--计算一笔租片费用         double result = 0;                  switch(get_movie().get_priceCode()){  //--取得影片出租价格             case Movie.REGULAR: //--普通片                 result += 2;                 if (get_daysRented() > 2)                     result += (get_daysRented() - 2) * 1.5;                 break;             case Movie.NEW_RELEASE:  //--新片                 result += get_daysRented() * 3;                 break;             case Movie.CHILDRENS: //--儿童片                 result += 1.5;                 if (get_daysRented() > 3)                     result += (get_daysRented() - 3) * 1.5;                 break;         }                  return result;     }     int getFrequentRenterPoints() {         if (get_movie().get_priceCode() == Movie.NEW_RELEASE &&             get_daysRented() > 1)             return 2;         else             return 1;     } }


    最新回复(0)