起点:编写3个类的代码
1、第一个类-影片(Movie):
package com.lee.test.aFirstExample;
public class Movie {
/**
* @param title
* @param priceCode
*/
public Movie(String title, int priceCode) {
super();
this.title = title;
this.priceCode = priceCode;
}
public static final int childrens = 2;
public static final int regular = 0;
public static final int new_release = 1;
private String title;
private int priceCode;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getPriceCode() {
return priceCode;
}
public void setPriceCode(int priceCode) {
this.priceCode = priceCode;
}
}
2、第二个类-租赁(Rental):
package com.lee.test.aFirstExample;
public class Rental {
/**
* @param movie
* @param dayRented
*/
public Rental(Movie movie, int dayRented) {
super();
this.movie = movie;
this.dayRented = dayRented;
}
private Movie movie;
public Movie getMovie() {
return movie;
}
private int dayRented;
public int getDayRented() {
return dayRented;
}
}
3、第三个类-消费者(Customer):
package com.lee.test.aFirstExample;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
/**
* @param name
*/
public Customer(String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
private Vector rentals = new Vector();
public void addRental(Rental arg)
{
rentals.addElement(arg);
}
public String statement(){
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
double thisAmount = 0;
Rental each = (Rental) rentalss.nextElement();
switch(each.getMovie().getPriceCode())
{
case Movie.regular:
thisAmount += 2;
if(each.getDayRented()>2)
thisAmount += (each.getDayRented()-2)*1.5;
break;
case Movie.new_release:
thisAmount += each.getDayRented()*3;
break;
case Movie.childrens:
thisAmount += 1.5;
if(each.getDayRented()>3)
thisAmount += (each.getDayRented()-3)*1.5;
break;
}
//积分 每借一张加1个积分
frequentRenterPoints++;
//积分累加条件 新版本的片子,借的时间大于1天
if((each.getMovie().getPriceCode()==Movie.new_release)&&each.getDayRented()>1)
{
frequentRenterPoints++;
}
result +="\t" +each.getMovie().getTitle()+"\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;
}
}
4、自己定义客户端(Client)。
package com.lee.test.aFirstExample;
public class Client {
public static void main(String[] args) {
Movie mov = new Movie("metal",2);
Rental ren = new Rental(mov,8);
Customer cus = new Customer("Lee");
cus.addRental(ren);
System.out.println(cus.statement());
}
}
5、输出结果
Rental Record for Lee
metal 9.0
Amount owed is 9.0
You earned 1 frequent renter points
6、重构第一步
提炼方法(Extract Method)
提炼Switch/Case分支到一个方法,修改后Customer代码:
package com.lee.test.aFirstExample;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
/**
* @param name
*/
public Customer(String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
private Vector rentals = new Vector();
public void addRental(Rental arg)
{
rentals.addElement(arg);
}
public String statement(){
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
double thisAmount = 0;
Rental each = (Rental) rentalss.nextElement();
thisAmount = amountFor(each); //提炼方法
/*switch(each.getMovie().getPriceCode())
{
case Movie.regular:
thisAmount += 2;
if(each.getDayRented()>2)
thisAmount += (each.getDayRented()-2)*1.5;
break;
case Movie.new_release:
thisAmount += each.getDayRented()*3;
break;
case Movie.childrens:
thisAmount += 1.5;
if(each.getDayRented()>3)
thisAmount += (each.getDayRented()-3)*1.5;
break;
}*/
//积分 每借一张加1个积分
frequentRenterPoints++;
//积分累加条件 新版本的片子,借的时间大于1天
if((each.getMovie().getPriceCode()==Movie.new_release)&&each.getDayRented()>1)
{
frequentRenterPoints++;
}
result +="\t" +each.getMovie().getTitle()+"\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.getMovie().getPriceCode())
{
case Movie.regular:
thisAmount += 2;
if(each.getDayRented()>2)
thisAmount += (each.getDayRented()-2)*1.5;
break;
case Movie.new_release:
thisAmount += each.getDayRented()*3;
break;
case Movie.childrens:
thisAmount += 1.5;
if(each.getDayRented()>3)
thisAmount += (each.getDayRented()-3)*1.5;
break;
}
return thisAmount;
}
}
备注:《Refactoring—Improving the Design of the Existing Code》书中说SmallTalk编译器具备重构功能,尝试使用Myeclipse 2015编译器使用。
操作过程:
(1) 选中需要重构的代码片段;
(2) IDE编译器的功能导航;
(4)用Myeclipse 2015编译器自动重构的代码如下,用Client客户端调用结果一致,修改后Customer代码:
package com.lee.test.aFirstExample;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
/**
* @param name
*/
public Customer(String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
private Vector rentals = new Vector();
public void addRental(Rental arg)
{
rentals.addElement(arg);
}
public String statement(){
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
double thisAmount = 0;
Rental each = (Rental) rentalss.nextElement();
// thisAmount = amountFor(each); //提炼方法
thisAmount = amountFor(thisAmount, each);
//积分 每借一张加1个积分
frequentRenterPoints++;
//积分累加条件 新版本的片子,借的时间大于1天
if((each.getMovie().getPriceCode()==Movie.new_release)&&each.getDayRented()>1)
{
frequentRenterPoints++;
}
result +="\t" +each.getMovie().getTitle()+"\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;
}
/**
* @param thisAmount
* @param each
* @return
*/
private double amountFor(double thisAmount, Rental each) {
switch(each.getMovie().getPriceCode())
{
case Movie.regular:
thisAmount += 2;
if(each.getDayRented()>2)
thisAmount += (each.getDayRented()-2)*1.5;
break;
case Movie.new_release:
thisAmount += each.getDayRented()*3;
break;
case Movie.childrens:
thisAmount += 1.5;
if(each.getDayRented()>3)
thisAmount += (each.getDayRented()-3)*1.5;
break;
}
return thisAmount;
}
/*private double amountFor(Rental each)
{
double thisAmount = 0;
switch(each.getMovie().getPriceCode())
{
case Movie.regular:
thisAmount += 2;
if(each.getDayRented()>2)
thisAmount += (each.getDayRented()-2)*1.5;
break;
case Movie.new_release:
thisAmount += each.getDayRented()*3;
break;
case Movie.childrens:
thisAmount += 1.5;
if(each.getDayRented()>3)
thisAmount += (each.getDayRented()-3)*1.5;
break;
}
return thisAmount;
}*/
}
7、重构第二步
移动方法(Move Method)
将amountFor()方法从Customer类中移动到Rental类中,并修改方法名称为getCharge()。
移动amountFor()方法后的Customer代码:
package com.lee.test.aFirstExample;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
/**
* @param name
*/
public Customer(String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
private Vector rentals = new Vector();
public void addRental(Rental arg)
{
rentals.addElement(arg);
}
public String statement(){
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
double thisAmount = 0;
Rental each = (Rental) rentalss.nextElement();
// thisAmount = amountFor(each); //提炼方法
thisAmount = each.getCharge(thisAmount);
//积分 每借一张加1个积分
frequentRenterPoints++;
//积分累加条件 新版本的片子,借的时间大于1天
if((each.getMovie().getPriceCode()==Movie.new_release)&&each.getDayRented()>1)
{
frequentRenterPoints++;
}
result +="\t" +each.getMovie().getTitle()+"\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.getMovie().getPriceCode())
{
case Movie.regular:
thisAmount += 2;
if(each.getDayRented()>2)
thisAmount += (each.getDayRented()-2)*1.5;
break;
case Movie.new_release:
thisAmount += each.getDayRented()*3;
break;
case Movie.childrens:
thisAmount += 1.5;
if(each.getDayRented()>3)
thisAmount += (each.getDayRented()-3)*1.5;
break;
}
return thisAmount;
}*/
}
移动amountFor()方法后的Rental代码:
package com.lee.test.aFirstExample;
public class Rental {
/**
* @param movie
* @param dayRented
*/
public Rental(Movie movie, int dayRented) {
super();
this.movie = movie;
this.dayRented = dayRented;
}
private Movie movie;
public Movie getMovie() {
return movie;
}
private int dayRented;
public int getDayRented() {
return dayRented;
}
/**
* @param thisAmount
* @return
*/
double getCharge(double thisAmount) {
switch(getMovie().getPriceCode())
{
case Movie.regular:
thisAmount += 2;
if(getDayRented()>2)
thisAmount += (getDayRented()-2)*1.5;
break;
case Movie.new_release:
thisAmount += getDayRented()*3;
break;
case Movie.childrens:
thisAmount += 1.5;
if(getDayRented()>3)
thisAmount += (getDayRented()-3)*1.5;
break;
}
return thisAmount;
}
}
8、重构第三步
以查询取代临时变量(Replace temp with query)
除去临时变量thisAmount;
修改后的statement账单方法:
public String statement(){
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
// thisAmount = amountFor(each); //提炼方法
//积分 每借一张加1个积分
frequentRenterPoints++;
//积分累加条件 新版本的片子,借的时间大于1天
if((each.getMovie().getPriceCode()==Movie.new_release)&&each.getDayRented()>1)
{
frequentRenterPoints++;
}
result +="\t" +each.getMovie().getTitle()+"\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;
}
修改Rental类的getCharge()方法,由传参改为内部变量:
double getCharge() {
double result = 0;
switch(getMovie().getPriceCode())
{
case Movie.regular:
result += 2;
if(getDayRented()>2)
result += (getDayRented()-2)*1.5;
break;
case Movie.new_release:
result += getDayRented()*3;
break;
case Movie.childrens:
result += 1.5;
if(getDayRented()>3)
result += (getDayRented()-3)*1.5;
break;
}
return result;
}
9、重构第四步:
提取方法提取“常客积分计算”:
int getFrequentRenterPoints() {
//积分累加条件 新版本的片子,借的时间大于1天
if((getMovie().getPriceCode()==Movie.new_release)&&getDayRented()>1)
{
return 2;
}
return 1;
}
10、重构第五步:
移动方法(Move Method)
将getFrequentRenterPoints()方法从Customer类中移动到Rental类中。
11、重构第六步:
以查询取代临时变量(Replace temp with query)
除去临时变量thisAmount;
除去临时变量frequentRenterPoints;
修改后的Customer类代码:
public String statement(){
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
result +="\t" +each.getMovie().getTitle()+"\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 points = 0;
Enumeration rentalss = rentals.elements();
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
points += each.getFrequentRenterPoints();
}
return points;
}
private double getTotalCharge()
{
double result = 0;
Enumeration rentalss = rentals.elements();
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
result += each.getCharge();
}
return result;
}
12、重构第七步:
将影片相关的费用、积分方法Move到Movie类中,将Rental的属性daysRented作为参数。
修改后的Rental类:
package com.lee.test.aFirstExample;
public class Rental {
/**
* @param movie
* @param dayRented
*/
public Rental(Movie movie, int dayRented) {
super();
this.movie = movie;
this.dayRented = dayRented;
}
private Movie movie;
public Movie getMovie() {
return movie;
}
private int dayRented;
public int getDayRented() {
return dayRented;
}
}
修改后的Movie类:
package com.lee.test.aFirstExample;
public class Movie {
/**
* @param title
* @param priceCode
*/
public Movie(String title, int priceCode) {
super();
this.title = title;
this.priceCode = priceCode;
}
public static final int childrens = 2;
public static final int regular = 0;
public static final int new_release = 1;
private String title;
private int priceCode;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getPriceCode() {
return priceCode;
}
public void setPriceCode(int priceCode) {
this.priceCode = priceCode;
}
/**
* @param daysRented
* @return
*/
double getCharge(int daysRented) {
double result = 0;
switch(getPriceCode())
{
case Movie.regular:
result += 2;
if(daysRented>2)
result += (daysRented-2)*1.5;
break;
case Movie.new_release:
result += daysRented*3;
break;
case Movie.childrens:
result += 1.5;
if(daysRented>3)
result += (daysRented-3)*1.5;
break;
}
return result;
}
/**
* @param daysRented
* @return
*/
int getFrequentRenterPoints(int daysRented) {
//积分累加条件 新版本的片子,借的时间大于1天
if((getPriceCode()== Movie.new_release) && daysRented>1)
{
return 2;
}
return 1;
}
}
修改后的Customer类:
package com.lee.test.aFirstExample;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
/**
* @param name
*/
public Customer(String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
private Vector rentals = new Vector();
public void addRental(Rental arg)
{
rentals.addElement(arg);
}
public String statement(){
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
result +="\t" +each.getMovie().getTitle()+"\t"
+String.valueOf(each.getMovie().getCharge(each.getDayRented()))+"\n";
}
result += "Amount owed is "+ String.valueOf(getTotalCharge())+"\n";
result +="You earned "+String.valueOf(getTotalFrequentRenterPoints())+" "
+"frequent renter points";
return result;
}
private int getTotalFrequentRenterPoints() {
int points = 0;
Enumeration rentalss = rentals.elements();
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
points += each.getMovie().getFrequentRenterPoints(each.getDayRented());
}
return points;
}
private double getTotalCharge()
{
double result = 0;
Enumeration rentalss = rentals.elements();
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
result += each.getMovie().getCharge(each.getDayRented());
}
return result;
}
}
13、重构第八步:
运用多态取代与价格相关的条件逻辑。
创建Price价格类,作为抽象类给多种影片类型继承,关联到Movie影片类中,Price类:
package com.lee.test.aFirstExample;
public abstract class Price {
abstract int getPriceCode();
abstract double getCharge(int daysRented);
}
分别创建3个不同价格类型的类:
NewReleasePrice类:
package com.lee.test.aFirstExample;
public class NewReleasePrice extends Price{
@Override
int getPriceCode() {
return Movie.new_release;
}
double getCharge(int daysRented)
{
double result = 0;
result += daysRented*3;
return result;
}
}
ChildrensPrice 类:
package com.lee.test.aFirstExample;
public class ChildrensPrice extends Price{
@Override
int getPriceCode() {
return Movie.childrens;
}
double getCharge(int daysRented)
{
double result = 0;
result += 1.5;
if(daysRented>3)
result += (daysRented-3)*1.5;
return result;
}
}
RegularPrice 类:
package com.lee.test.aFirstExample;
public class RegularPrice extends Price{
@Override
int getPriceCode() {
return Movie.regular;
}
double getCharge(int daysRented)
{
double result = 0;
result += 2;
if(daysRented>2)
result += (daysRented-2)*1.5;
return result;
}
}
修改后的Movie类:
package com.lee.test.aFirstExample;
public class Movie {
/**
* @param title
* @param priceCode
*/
public Movie(String title, int priceCode) {
super();
this.title = title;
this.priceCode = priceCode;
}
public static final int childrens = 2;
public static final int regular = 0;
public static final int new_release = 1;
private String title;
private int priceCode;
private Price price;
public Price getPrice() {
return price;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getPriceCode() {
return price.getPriceCode();
}
public void setPriceCode(int arg) {
switch(arg)
{
case regular:
price = new RegularPrice();
break;
case new_release:
price = new NewReleasePrice();
break;
case childrens:
price = new ChildrensPrice();
break;
default:
throw new IllegalArgumentException("Incorrect Price Code");
}
}
/**
* @param daysRented
* @return
*/
int getFrequentRenterPoints(int daysRented) {
//积分累加条件 新版本的片子,借的时间大于1天
if((getPriceCode()== Movie.new_release) && daysRented>1)
{
return 2;
}
return 1;
}
}
Rental类:
package com.lee.test.aFirstExample;
public class Rental {
/**
* @param movie
* @param dayRented
*/
public Rental(Movie movie, int dayRented) {
super();
this.movie = movie;
this.dayRented = dayRented;
}
private Movie movie;
public Movie getMovie() {
return movie;
}
private int dayRented;
public int getDayRented() {
return dayRented;
}
}
Customer类:
package com.lee.test.aFirstExample;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
/**
* @param name
*/
public Customer(String name) {
super();
this.name = name;
}
private String name;
public String getName() {
return name;
}
private Vector rentals = new Vector();
public void addRental(Rental arg)
{
rentals.addElement(arg);
}
public String statement(){
Enumeration rentalss = rentals.elements();
String result = "Rental Record for" +" "+ getName()+"\n";
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
result +="\t" +each.getMovie().getTitle()+"\t"
+String.valueOf(each.getMovie().getPrice().getCharge(each.getDayRented()))+"\n";
}
result += "Amount owed is "+ String.valueOf(getTotalCharge())+"\n";
result +="You earned "+String.valueOf(getTotalFrequentRenterPoints())+" "
+"frequent renter points";
return result;
}
private int getTotalFrequentRenterPoints() {
int points = 0;
Enumeration rentalss = rentals.elements();
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
points += each.getMovie().getFrequentRenterPoints(each.getDayRented());
}
return points;
}
private double getTotalCharge()
{
double result = 0;
Enumeration rentalss = rentals.elements();
while(rentalss.hasMoreElements())
{
Rental each = (Rental) rentalss.nextElement();
result += each.getMovie().getPrice().getCharge(each.getDayRented());
}
return result;
}
}
运行的Client:
package com.lee.test.aFirstExample;
public class Client {
public static void main(String[] args) {
Movie mov1 = new Movie("metal",2);
mov1.setPriceCode(2);
Rental ren = new Rental(mov1,8);
Movie mov2 = new Movie("apple",1);
mov2.setPriceCode(1);
Rental xxx = new Rental(mov2,6);
Customer cus = new Customer("Lee");
cus.addRental(ren);
cus.addRental(xxx);
System.out.println(cus.statement());
}
}
打印输出结果:
Rental Record for Lee
metal 9.0
apple 18.0
Amount owed is 27.0
You earned 3 frequent renter points