`
381895649
  • 浏览: 227772 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

java 代码重构-第一章(终于…我们来到继承(Inheritance))

    博客分类:
  • java
阅读更多

 

上一篇文章:java 代码重构-第一章(运用多态(Polymorphism)取代与价格相关的条件逻辑)

下一篇文章:java 代码重构-第一章(使用策略模式,把恶心的switch代码去掉...) 一

 

终于……我们来到继承(Inheritance)

我们有数种影片类型,它们以不同的方式回答相同的问题。这听起来很像subclasses 的工作。我们可以建立Movie 的三个subclasses ,每个都有自己的计费法(图1.14)。

这么一来我就可以运用多态(polymorphism)来取代switch 语句了。很遗憾的是这里有个小问题,不能这么干。一部影片可以在生命周期内修改自己的分类,一个对象却不能在生命周期内修改自己所属的class。不过还是有一个解决方法:State pattern(模式)[Gang of Four]。运用它之后,我们的classes 看起来像图1.15。

 

加入这一层间接性,我们就可以在Price 对象内进行subclassing 动作(译注:一如图1.15),于是便可在任何必要时刻修改价格。

 

如果你很熟悉Gang of Four 所列的各种模式(patterns),你可能会问:『这是一个State 还是一个Strategy?』答案取决于Price class 究竟代表计费方式(此时我喜欢把它叫做Pricer 或PricingStrategy),或是代表影片的某个状态(state,例如「Star Trek X 是一部新片」)。在这个阶段,对于模式(和其名称)的选择反映出你对结构的想法。此刻我把它视为影片的某种状态(state)。如果未来我觉得Strategy 能更好地说明我的意图,我会再重构它,修改名字,以形成Strategy 。

 

为了引入State 模式,我使用三个重构准则。首先运用Replace Type Code with State/Strategy,将「与型别相依的行为」(type code behavior )搬移至State 模式内。然后运用Move Method 将switch 语句移到Price class 里头。最后运用Replace Conditional with Polymorphism去掉switch 语句。

 

首先我要使用Replace Type Code with State/Strategy。第一步骤是针对「与 型别相依的行为」使用Self Encapsulate Field,确保任何时候都通过getting 和setting 两个函数来运用这些行为。由于多数代码来自其他classes,所以多数函数都己经使用getting 函数。但构造函数(constructor )仍然直接访问价格代号(译注:程序中的priceCode):

 

public Movie(String title, int priceCode) {
		this.title = title;
		this.priceCode = priceCode;
	}

 然后编译并测试,确保没有破坏任何东西。

 

输出结果:

 

Rental Record for oyhk 
	少林足球	6.0
	大话西游	1.5
Amount owed is 7.5
You earned 3 frequent renter points
------------------------------------------------
<H1>Rentals for <EM>oyhk</EM></ H1><P>
少林足球: 6.0<BR>
大话西游: 1.5<BR>
<P>You owe <EM>7.5</EM><P>
On this rental you earned <EM>3</EM> frequent renter points<P>

 证明重构没有错,结果跟上次的一样

 

下面是完整的代码:

Movie

 

package com.mkfree.refactoring.shap1;

/**
 * 电影类
 * 
 * @author hk
 * 
 *         2012-12-25 下午10:55:14
 */
public class Movie {

	public static final int CHILDRENS = 2;
	public static final int REGULAR = 0;
	public static final int NEW_RELEASE = 1;

	public Movie(String title, int priceCode) {
		this.title = title;
		this.priceCode = priceCode;
	}

	private String title;
	private int priceCode;

	public String getTitle() {
		return title;
	}

	public int getPriceCode() {
		return 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;

	}

	int getFrequentRenterPoints(int daysRented) {
		if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)
			return 2;
		else
			return 1;
	}

}

 Rental

 

 

 

package com.mkfree.refactoring.shap1;

/**
 * 租凭
 * 
 * @author hk
 * 
 *         2012-12-25 下午10:57:00
 */
public class Rental {

	private Movie movie;
	private int daysRented;

	public Rental(Movie movie, int daysRented) {
		this.movie = movie;
		this.daysRented = daysRented;
	}

	public Movie getMovie() {
		return movie;
	}

	public int getDaysRented() {
		return daysRented;
	}

	/**
	 * 把代码迁移到movie中
	 * 
	 * @return
	 */
	double getCharge() {
		return this.getMovie().getCharge(daysRented);
	}

	/**
	 * 获取经常的租赁
	 * 
	 * @return
	 */
	int getFrequentRenterPoints() {
		return this.getMovie().getFrequentRenterPoints(daysRented);
	}
}
 

 

Customer

 

package com.mkfree.refactoring.shap1;

import java.util.Enumeration;
import java.util.Vector;

/**
 * 顾客
 * 
 * @author hk
 * 
 *         2012-12-25 下午10:59:03
 */
public class Customer {

	private String name;
	private Vectorrentals = new Vector<>();

	public Customer(String name) {
		this.name = name;
	}

	/**
	 * 添加
	 * 
	 * @param rental
	 */
	public void addRentals(Rental rental) {
		rentals.add(rental);
	}

	public String getName() {
		return name;
	}

	/**
	 * 通计清单
	 * 
	 * @return
	 */
	public String statement() {
		Enumerationenu_rentals = rentals.elements();
		String result = "Rental Record for " + this.getName() + " \n";
		while (enu_rentals.hasMoreElements()) {
			Rental each = enu_rentals.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;
	}

	// 此即所谓query method
	private double getTotalCharge() {
		double result = 0;
		Enumerationenu_rentals = rentals.elements();
		while (enu_rentals.hasMoreElements()) {
			Rental each = (Rental) enu_rentals.nextElement();
			result += each.getCharge();
		}
		return result;
	}

	// 此即所谓query method
	private int getTotalFrequentRenterPoints() {
		int result = 0;
		Enumerationenu_rentals = rentals.elements();
		while (enu_rentals.hasMoreElements()) {
			Rental each = (Rental) enu_rentals.nextElement();
			result += each.getFrequentRenterPoints();
		}
		return result;
	}

}

 

 Client

 

package com.mkfree.refactoring.shap1;

import org.junit.Test;

public class Client {

	@Test
	public void testStatement() {

		Movie movie1 = new Movie("少林足球", 1);
		Rental rental1 = new Rental(movie1, 2);

		Movie movie2 = new Movie("大话西游", 2);
		Rental rental2 = new Rental(movie2, 3);

		Customer customer = new Customer("oyhk");
		customer.addRentals(rental1);
		customer.addRentals(rental2);
		String statement = customer.statement();
		System.out.println(statement);
		System.out.println("------------------------------------------------");
		String htmlStatment = customer.htmlStatement();
		System.out.println(htmlStatment);
	}
}

 由于重构了Movie代码,对于Client当然也修改了一点点了...

 

本文章来自:http://blog.mkfree.com/posts/28

  • 大小: 24.4 KB
  • 大小: 24 KB
1
4
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics